The plane returns to the airport from which it took off
There is one problem, that on touch down the plane is going underground on the short while.
This commit is contained in:
parent
cbc1888425
commit
f3d50cc815
@ -49,6 +49,7 @@ var loadExtraNasalFiles = func (addon) {
|
|||||||
"nasal/dialogs/thermal",
|
"nasal/dialogs/thermal",
|
||||||
"nasal/flight-plan",
|
"nasal/flight-plan",
|
||||||
"nasal/scenario",
|
"nasal/scenario",
|
||||||
|
"nasal/io/waypoint",
|
||||||
"nasal/io/flight-plan-writer",
|
"nasal/io/flight-plan-writer",
|
||||||
"nasal/aerotow",
|
"nasal/aerotow",
|
||||||
"aerotow",
|
"aerotow",
|
||||||
|
@ -36,7 +36,6 @@ var FlightPlan = {
|
|||||||
|
|
||||||
obj.addonNodePath = addon.node.getPath();
|
obj.addonNodePath = addon.node.getPath();
|
||||||
|
|
||||||
obj.wptCount = 0;
|
|
||||||
obj.coord = nil; # Coordinates for flight plan
|
obj.coord = nil; # Coordinates for flight plan
|
||||||
obj.heading = nil; # AI plane heading
|
obj.heading = nil; # AI plane heading
|
||||||
obj.altitude = nil; # AI plane altitude
|
obj.altitude = nil; # AI plane altitude
|
||||||
@ -70,10 +69,11 @@ var FlightPlan = {
|
|||||||
if (rwyResult.distance > FlightPlan.MAX_RUNWAY_DISTANCE) {
|
if (rwyResult.distance > FlightPlan.MAX_RUNWAY_DISTANCE) {
|
||||||
# The runway is too far away, we assume a bush start
|
# The runway is too far away, we assume a bush start
|
||||||
return {
|
return {
|
||||||
"type" : "bush",
|
"type" : "bush",
|
||||||
"lat" : gliderCoord.lat(),
|
"lat" : gliderCoord.lat(),
|
||||||
"lon" : gliderCoord.lon(),
|
"lon" : gliderCoord.lon(),
|
||||||
"heading" : getprop("/orientation/heading-deg"),
|
"heading" : getprop("/orientation/heading-deg"),
|
||||||
|
"elevation": me.getEleveationInFt(gliderCoord),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,10 +89,14 @@ var FlightPlan = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"type" : "runway",
|
"type" : "runway",
|
||||||
"lat" : rwyResult.runway.lat,
|
"lat" : rwyResult.runway.lat,
|
||||||
"lon" : rwyResult.runway.lon,
|
"lon" : rwyResult.runway.lon,
|
||||||
"heading" : rwyResult.runway.heading,
|
"heading" : rwyResult.runway.heading,
|
||||||
|
"elevation": me.getEleveationInFt(
|
||||||
|
geo.Coord.new().set_latlon(rwyResult.runway.lat, rwyResult.runway.lon)
|
||||||
|
),
|
||||||
|
"length" : rwyResult.runway.length,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -149,11 +153,11 @@ var FlightPlan = {
|
|||||||
var wptData = [
|
var wptData = [
|
||||||
{"hdgChange": 0, "dist": 5000, "altChange": aircraft.vs * 5},
|
{"hdgChange": 0, "dist": 5000, "altChange": aircraft.vs * 5},
|
||||||
{"hdgChange": -90, "dist": 1000, "altChange": aircraft.vs},
|
{"hdgChange": -90, "dist": 1000, "altChange": aircraft.vs},
|
||||||
{"hdgChange": -90, "dist": 1000, "altChange": aircraft.vs},
|
{"hdgChange": -90, "dist": 6000, "altChange": aircraft.vs * 6},
|
||||||
{"hdgChange": 0, "dist": 5000, "altChange": aircraft.vs * 5},
|
|
||||||
{"hdgChange": -90, "dist": 1500, "altChange": aircraft.vs * 1.5},
|
{"hdgChange": -90, "dist": 1500, "altChange": aircraft.vs * 1.5},
|
||||||
{"hdgChange": -90, "dist": 1000, "altChange": aircraft.vs},
|
{"hdgChange": -90, "dist": 6000, "altChange": aircraft.vs * 6},
|
||||||
{"hdgChange": 0, "dist": 5000, "altChange": aircraft.vs * 5},
|
{"hdgChange": 0, "dist": 0, "altChange": 0},
|
||||||
|
{"hdgChange": 0, "dist": 0, "altChange": 0},
|
||||||
{"hdgChange": 0, "dist": 0, "altChange": 0},
|
{"hdgChange": 0, "dist": 0, "altChange": 0},
|
||||||
{"hdgChange": 0, "dist": 0, "altChange": 0},
|
{"hdgChange": 0, "dist": 0, "altChange": 0},
|
||||||
{"hdgChange": 0, "dist": 0, "altChange": 0},
|
{"hdgChange": 0, "dist": 0, "altChange": 0},
|
||||||
@ -164,20 +168,20 @@ var FlightPlan = {
|
|||||||
# 1 - 1st waypoint
|
# 1 - 1st waypoint
|
||||||
# 2 - 2nd waypoint, etc.
|
# 2 - 2nd waypoint, etc.
|
||||||
#
|
#
|
||||||
# 2 . . 1 7
|
# 2 . . 1 5
|
||||||
# . . .
|
|
||||||
# . . .
|
|
||||||
# 3 . .
|
|
||||||
# . . .
|
# . . .
|
||||||
# . . .
|
# . . .
|
||||||
# . . .
|
# . . .
|
||||||
# . . .
|
# . . .
|
||||||
# . . .
|
# . . .
|
||||||
# . . .
|
# . . .
|
||||||
# . ^ 6
|
# . . .
|
||||||
|
# . . .
|
||||||
|
# . . .
|
||||||
|
# . ^ .
|
||||||
# . .
|
# . .
|
||||||
# . .
|
# . .
|
||||||
# 4 . . . . 5
|
# 3 . . . . 4
|
||||||
|
|
||||||
var index = 0;
|
var index = 0;
|
||||||
foreach (var wpt; wptData) {
|
foreach (var wpt; wptData) {
|
||||||
@ -202,8 +206,6 @@ var FlightPlan = {
|
|||||||
# Return true on successful, otherwise false.
|
# Return true on successful, otherwise false.
|
||||||
#
|
#
|
||||||
generateXml: func () {
|
generateXml: func () {
|
||||||
me.wptCount = 0;
|
|
||||||
|
|
||||||
var location = me.getLocation();
|
var location = me.getLocation();
|
||||||
if (location == nil) {
|
if (location == nil) {
|
||||||
return false;
|
return false;
|
||||||
@ -218,7 +220,7 @@ var FlightPlan = {
|
|||||||
|
|
||||||
# Start at 2 o'clock from the glider...
|
# Start at 2 o'clock from the glider...
|
||||||
# Inital ktas must be >= 1.0
|
# Inital ktas must be >= 1.0
|
||||||
me.addWptGround({"hdgChange": 60, "dist": 25}, {"altChange": 0, "ktas": 5});
|
me.addWptGround({"shift": {"hdgChange": 60, "dist": 25, "altChange": 0}, "ktas": 5}); # 1
|
||||||
|
|
||||||
# Reset coord and heading
|
# Reset coord and heading
|
||||||
isGliderPos = false;
|
isGliderPos = false;
|
||||||
@ -227,26 +229,26 @@ var FlightPlan = {
|
|||||||
var gliderOffsetM = me.getGliderOffsetFromRunwayThreshold(location);
|
var gliderOffsetM = me.getGliderOffsetFromRunwayThreshold(location);
|
||||||
|
|
||||||
# ... and line up with the runway
|
# ... and line up with the runway
|
||||||
me.addWptGround({"hdgChange": 0, "dist": me.getInitialDistance() + gliderOffsetM}, {"altChange": 0, "ktas": 2.5});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": me.getInitialDistance() + gliderOffsetM, "altChange": 0}, "ktas": 2.5}); # 2
|
||||||
|
|
||||||
# Rolling
|
# Rolling
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10}, {"altChange": 0, "ktas": 5});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10, "altChange": 0}, "ktas": 5}); # 3
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 20}, {"altChange": 0, "ktas": 5});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 20, "altChange": 0}, "ktas": 5}); # 4
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 20}, {"altChange": 0, "ktas": aircraft.speed / 6});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 20, "altChange": 0}, "ktas": aircraft.speed / 6}); # 5
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10}, {"altChange": 0, "ktas": aircraft.speed / 5});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10, "altChange": 0}, "ktas": aircraft.speed / 5}); # 6
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed / 4});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed / 4}); # 7
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed / 3.5});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed / 3.5}); # 8
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed / 3});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed / 3}); # 9
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed / 2.5});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed / 2.5}); # 10
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed / 2});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed / 2}); # 11
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed / 1.75});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed / 1.75}); # 12
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed / 1.5});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed / 1.5}); # 13
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed / 1.25});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed / 1.25}); # 14
|
||||||
me.addWptGround({"hdgChange": 0, "dist": 10 * aircraft.rolling}, {"altChange": 0, "ktas": aircraft.speed});
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 10 * aircraft.rolling, "altChange": 0}, "ktas": aircraft.speed}); # 15
|
||||||
|
|
||||||
# Take-off
|
# Take-off
|
||||||
me.addWptAir({"hdgChange": 0, "dist": 100 * aircraft.rolling}, {"elevationPlus": 3, "ktas": aircraft.speed * 1.05});
|
me.addWptAir({ "shift": {"hdgChange": 0, "dist": 100 * aircraft.rolling, "elevation": 3}, "ktas": aircraft.speed * 1.05}); # 16
|
||||||
me.addWptAir({"hdgChange": 0, "dist": 100}, {"altChange": aircraft.vs / 10, "ktas": aircraft.speed * 1.025});
|
me.addWptAir({ "shift": {"hdgChange": 0, "dist": 100, "altChange": aircraft.vs / 10}, "ktas": aircraft.speed * 1.025}); # 17
|
||||||
|
|
||||||
|
|
||||||
# 0 means without altitude limits
|
# 0 means without altitude limits
|
||||||
@ -281,10 +283,86 @@ var FlightPlan = {
|
|||||||
|
|
||||||
totalAlt += altChange;
|
totalAlt += altChange;
|
||||||
|
|
||||||
me.addWptAir({"hdgChange": hdgChange, "dist": distance}, {"altChange": altChange, "ktas": ktas});
|
me.addWptAir({"shift": {"hdgChange": hdgChange, "dist": distance, "altChange": altChange}, "ktas": ktas});
|
||||||
}
|
}
|
||||||
|
|
||||||
me.addWptEnd();
|
# Back to airport if possible
|
||||||
|
if (location.type == "runway") {
|
||||||
|
# Add extra near waypoint to keep plane in whole designed track
|
||||||
|
me.addWptAir({"shift": {"hdgChange": hdgChange, "dist": 100, "altChange": altChange}, "ktas": ktas});
|
||||||
|
|
||||||
|
var coordRwyThreshold = geo.Coord.new().set_latlon(location.lat, location.lon);;
|
||||||
|
|
||||||
|
# Check distance to runway threshold
|
||||||
|
var dostanceToThreshold = me.coord.distance_to(coordRwyThreshold);
|
||||||
|
|
||||||
|
# Reset variables
|
||||||
|
me.heading = location.heading; # runway heading
|
||||||
|
me.coord = coordRwyThreshold;
|
||||||
|
|
||||||
|
# Move o the left of the runway threshold
|
||||||
|
me.heading = me.correctHeading(me.heading - 90);
|
||||||
|
me.coord.apply_course_distance(me.heading, 1000);
|
||||||
|
|
||||||
|
# Add a waypoint to the left of the runway + 3000 m to the middle of length
|
||||||
|
# Descend as far as you can to max elevation + 3000 ft
|
||||||
|
var halfRwyLenght = location.length / 2;
|
||||||
|
var altAgl = me.altitude - location.elevation;
|
||||||
|
var elevation = altAgl - (aircraft.getAltChange(dostanceToThreshold) * 2);
|
||||||
|
if (elevation < 3000) {
|
||||||
|
elevation = 3000;
|
||||||
|
}
|
||||||
|
me.addWptAir({"shift": {"hdgChange": 90, "dist": halfRwyLenght, "elevation": elevation}, "ktas": aircraft.speed});
|
||||||
|
|
||||||
|
# Fly downwind away of threshold, how far depend of the altitude
|
||||||
|
var desiredElevation = 2000;
|
||||||
|
var distance = (((elevation - desiredElevation) / (aircraft.vs * 3)) * 1000);
|
||||||
|
if (distance < 3000) {
|
||||||
|
distance = 3000;
|
||||||
|
}
|
||||||
|
me.addWptAir({"shift": {"hdgChange": -180, "dist": halfRwyLenght + distance, "elevation": desiredElevation}, "ktas": aircraft.speed});
|
||||||
|
|
||||||
|
# Turn to base leg
|
||||||
|
me.addWptAir({"shift": {"hdgChange": -90, "dist": 1000, "elevation": 1000}, "ktas": aircraft.speed, "flapsDown": true});
|
||||||
|
|
||||||
|
# Reset variables
|
||||||
|
me.coord = geo.Coord.new().set_latlon(location.lat, location.lon); # runway threshold
|
||||||
|
|
||||||
|
# Turn on final
|
||||||
|
me.addWptAir({
|
||||||
|
"coord" : me.coord,
|
||||||
|
"crossAt" : location.elevation + 10,
|
||||||
|
"ktas" : aircraft.speed * 0.75,
|
||||||
|
"flapsDown": true,
|
||||||
|
"gearDown" : true,
|
||||||
|
});
|
||||||
|
|
||||||
|
# Reset variables
|
||||||
|
me.heading = location.heading;
|
||||||
|
|
||||||
|
# Flare
|
||||||
|
me.addWptAir({
|
||||||
|
"shift" : {"hdgChange": 0, "dist": 100, "elevation": 10},
|
||||||
|
"ktas" : aircraft.speed * 0.7,
|
||||||
|
"flapsDown": true,
|
||||||
|
"gearDown" : true,
|
||||||
|
});
|
||||||
|
|
||||||
|
# Touchdown
|
||||||
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 200, "elevation": 0}, "ktas": aircraft.speed * 0.6});
|
||||||
|
|
||||||
|
# Break
|
||||||
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 200, "elevation": 0}, "ktas": aircraft.speed * 0.4});
|
||||||
|
|
||||||
|
# Slow down to 5 kt
|
||||||
|
me.addWptGround({"shift": {"hdgChange": 0, "dist": 50, "elevation": 0}, "ktas": 5});
|
||||||
|
|
||||||
|
# Turn right out of runway and full stop
|
||||||
|
me.addWptEnd({"shift": {"hdgChange": 90, "dist": 100, "elevation": 0}, "ktas": 0, "onGround": true});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
me.addWptEnd();
|
||||||
|
}
|
||||||
|
|
||||||
me.flightPlanWriter.close();
|
me.flightPlanWriter.close();
|
||||||
|
|
||||||
@ -345,26 +423,24 @@ var FlightPlan = {
|
|||||||
#
|
#
|
||||||
# Add new waypoint on ground
|
# Add new waypoint on ground
|
||||||
#
|
#
|
||||||
# coordOffset - Hash for calculate next coordinates (lat, lon), with following fields:
|
# wptData - hash object with waypoint data
|
||||||
# {
|
|
||||||
# hdgChange - How the aircraft's heading supposed to change? 0 - keep the same heading.
|
|
||||||
# dis - Distance in meters to calculate next waypoint coordinates.
|
|
||||||
# }
|
|
||||||
# performance - Hash with following fields:
|
|
||||||
# {
|
|
||||||
# altChange - How the aircraft's altitude is supposed to change? 0 - keep the same altitude.
|
|
||||||
# ktas - True air speed of AI plane at the waypoint.
|
|
||||||
# }
|
|
||||||
#
|
#
|
||||||
addWptGround: func (coordOffset, performance) {
|
addWptGround: func (wptData) {
|
||||||
me.wrireWpt(nil, coordOffset, performance, "ground");
|
wptData.onGround = true;
|
||||||
|
me.addWpt(wptData);
|
||||||
},
|
},
|
||||||
|
|
||||||
#
|
#
|
||||||
# Add new waypoint in air
|
# Add new waypoint in air
|
||||||
#
|
#
|
||||||
addWptAir: func (coordOffset, performance) {
|
# wptData - hash object wtih waypoint data
|
||||||
me.wrireWpt(nil, coordOffset, performance, "air");
|
#
|
||||||
|
addWptAir: func (wptData) {
|
||||||
|
if (contains(wptData, "onGround")) {
|
||||||
|
wptData.onGround = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
me.addWpt(wptData);
|
||||||
},
|
},
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -373,70 +449,115 @@ var FlightPlan = {
|
|||||||
# sec - Number of seconds for wait
|
# sec - Number of seconds for wait
|
||||||
#
|
#
|
||||||
addWptWait: func (sec) {
|
addWptWait: func (sec) {
|
||||||
me.wrireWpt("WAIT", {}, {}, nil, sec);
|
me.addWpt({"waitSec": sec});
|
||||||
},
|
},
|
||||||
|
|
||||||
#
|
#
|
||||||
# Add "END" waypoint
|
# Add "END" waypoint with optional waypoint data
|
||||||
#
|
#
|
||||||
addWptEnd: func () {
|
addWptEnd: func (wptData = nil) {
|
||||||
me.wrireWpt("END", {}, {});
|
if (wptData == nil) {
|
||||||
|
wptData = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
wptData.name = "END";
|
||||||
|
|
||||||
|
me.addWpt(wptData);
|
||||||
},
|
},
|
||||||
|
|
||||||
#
|
#
|
||||||
# Write waypoint to flight plan file
|
# Add new waypoint with given waypoint data
|
||||||
#
|
#
|
||||||
# name - The name of waypoint
|
# wptData = {
|
||||||
# coordOffset.hdgChange - How the aircraft's heading supposed to change?
|
# shift: { - Optionally hash with data to calculate next coordinates (lat, lon) and altitude of waypoint
|
||||||
# coordOffset.dist - Distance in meters to calculate next waypoint coordinates
|
# hdgChange - How the aircraft's heading supposed to change? 0 - keep the same heading.
|
||||||
# performance.altChange - How the aircraft's altitude is supposed to change?
|
# dist - Distance in meters to calculate next waypoint coordinates.
|
||||||
# performance.elevationPlus - Set aircraft altitude as current terrain elevation + given value in feets.
|
# altChange - How the aircraft's altitude is supposed to change? 0 - keep the same altitude.
|
||||||
# It's best to use for the first point in the air to avoid the plane collapsing into
|
# elevation - Set aircraft altitude as current terrain elevation + given value in feets.
|
||||||
# the ground in a bumpy airport
|
# It's best to use for the first point in the air to avoid the plane collapsing into
|
||||||
# performance.ktas - True air speed of AI plane at the waypoint
|
# the ground in a bumpy airport.
|
||||||
# groundAir - Allowed value: "ground or "air". The "ground" means that AI plane is on the ground, "air" - in air
|
# },
|
||||||
# sec - Number of seconds for "WAIT" waypoint
|
# coord - The geo.Coord object, required if shift is not given
|
||||||
|
# crossAt - Altitude in feet, required if shift is not given
|
||||||
|
# ktas - True airspeed in knots, required
|
||||||
|
# onGround - If true then set on ground, otherwise set in air
|
||||||
|
# flapsDown - If true then set flaps down, otherwise set flaps up
|
||||||
|
# gearDown - If true then set gear down, otherwise set gear up
|
||||||
|
# waitSec - Number of seconds for WIAT waypoint
|
||||||
|
# }
|
||||||
#
|
#
|
||||||
wrireWpt: func (
|
addWpt: func (wptData) {
|
||||||
name,
|
if (contains(wptData, "shift")) {
|
||||||
coordOffset,
|
me.shiftWpt(wptData.shift);
|
||||||
performance,
|
|
||||||
groundAir = nil,
|
|
||||||
sec = nil
|
|
||||||
) {
|
|
||||||
var coord = nil;
|
|
||||||
if (contains(coordOffset, "hdgChange") and contains(coordOffset, "dist")) {
|
|
||||||
me.heading += coordOffset.hdgChange;
|
|
||||||
if (me.heading < 0) {
|
|
||||||
me.heading += 360;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (me.heading > 360) {
|
# Set coord and crossAt updated by shiftWpt()
|
||||||
me.heading -= 360;
|
wptData.coord = me.coord;
|
||||||
}
|
wptData.crossAt = me.altitude;
|
||||||
|
|
||||||
me.coord.apply_course_distance(me.heading, coordOffset.dist);
|
|
||||||
coord = me.coord;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var alt = nil;
|
var wpt = Waypoint.new().setHashData(wptData);
|
||||||
if (coord != nil and contains(performance, "elevationPlus")) {
|
|
||||||
var elevation = geo.elevation(coord.lat(), coord.lon());
|
me.flightPlanWriter.write(wpt);
|
||||||
me.altitude = elevation == nil
|
},
|
||||||
? me.altitude + performance.elevationPlus
|
|
||||||
: elevation * globals.M2FT + performance.elevationPlus;
|
#
|
||||||
alt = me.altitude;
|
# Calculate heading, coordinates and altitude from data in wptShift hash
|
||||||
}
|
#
|
||||||
else if (contains(performance, "altChange")) {
|
# wptShift - hash object with data
|
||||||
me.altitude += performance.altChange;
|
#
|
||||||
alt = me.altitude;
|
shiftWpt: func (wptShift) {
|
||||||
|
if (!contains(wptShift, "hdgChange")) {
|
||||||
|
die("ERROR aerotow add-on: missing 'hdgChange' for computeWptShift");
|
||||||
}
|
}
|
||||||
|
|
||||||
var ktas = contains(performance, "ktas") ? performance.ktas : nil;
|
if (!contains(wptShift, "dist")) {
|
||||||
|
die("ERROR aerotow add-on: missing 'dist' for computeWptShift");
|
||||||
|
}
|
||||||
|
|
||||||
name = name == nil ? me.wptCount : name;
|
# Shift heading and coordinates
|
||||||
me.flightPlanWriter.write(name, coord, alt, ktas, groundAir, sec);
|
me.heading = me.correctHeading(me.heading + wptShift.hdgChange);
|
||||||
|
me.coord.apply_course_distance(me.heading, wptShift.dist);
|
||||||
|
|
||||||
me.wptCount += 1;
|
if (contains(wptShift, "elevation")) {
|
||||||
|
# Set the altitude as the elevation for coordinates of the point plus the given elevation
|
||||||
|
me.altitude = me.getEleveationInFt(me.coord) + wptShift.elevation;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptShift, "altChange")) {
|
||||||
|
# Change altitude by given altChange
|
||||||
|
me.altitude += wptShift.altChange;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Correct the heading value that to be from 0 to 360
|
||||||
|
#
|
||||||
|
# heading - heading for correction
|
||||||
|
# Return heading in range from 0 to 360.
|
||||||
|
#
|
||||||
|
correctHeading: func (heading) {
|
||||||
|
if (heading < 0) {
|
||||||
|
heading += 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (heading > 360) {
|
||||||
|
heading -= 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
return heading;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Get elevation of given coordinates in feet
|
||||||
|
#
|
||||||
|
# coord - geo.Coord object
|
||||||
|
#
|
||||||
|
getEleveationInFt: func (coord) {
|
||||||
|
if (coord == nil) {
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
return geo.elevation(coord.lat(), coord.lon()) * globals.M2FT;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -23,6 +23,7 @@ var FlightPlanWriter = {
|
|||||||
|
|
||||||
obj.fpFileHandler = nil; # Handler for wrire flight plan to file
|
obj.fpFileHandler = nil; # Handler for wrire flight plan to file
|
||||||
obj.flightPlanPath = addon.storagePath ~ "/AI/FlightPlans/" ~ FlightPlan.FILENAME_FLIGHTPLAN;
|
obj.flightPlanPath = addon.storagePath ~ "/AI/FlightPlans/" ~ FlightPlan.FILENAME_FLIGHTPLAN;
|
||||||
|
obj.wptCount = 1;
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
},
|
},
|
||||||
@ -31,6 +32,8 @@ var FlightPlanWriter = {
|
|||||||
# Open XML file to wrire flight plan
|
# Open XML file to wrire flight plan
|
||||||
#
|
#
|
||||||
open: func () {
|
open: func () {
|
||||||
|
me.wptCount = 1;
|
||||||
|
|
||||||
me.fpFileHandler = io.open(me.flightPlanPath, "w");
|
me.fpFileHandler = io.open(me.flightPlanPath, "w");
|
||||||
|
|
||||||
if (me.fpFileHandler) {
|
if (me.fpFileHandler) {
|
||||||
@ -47,50 +50,61 @@ var FlightPlanWriter = {
|
|||||||
#
|
#
|
||||||
# Write single waypoint to XML file with flight plan
|
# Write single waypoint to XML file with flight plan
|
||||||
#
|
#
|
||||||
# name - Name of waypoint. Special names are: "WAIT", "END".
|
# wpt - Waypoint object
|
||||||
# coord - The Coord object
|
|
||||||
# alt - Altitude AMSL of AI plane
|
|
||||||
# ktas - True air speed of AI plane
|
|
||||||
# groundAir - Allowe value: "ground or "air". The "ground" means that AI plane is on the ground, "air" - in air
|
|
||||||
# sec - Number of seconds for "WAIT" waypoint
|
|
||||||
#
|
#
|
||||||
write: func (name, coord = nil, alt = nil, ktas = nil, groundAir = nil, sec = nil) {
|
write: func (wpt) {
|
||||||
if (!me.fpFileHandler) {
|
if (!me.fpFileHandler) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var str = " <wpt>\n"
|
if (wpt.name == nil) {
|
||||||
~ " <name>" ~ name ~ "</name>\n";
|
wpt.setName(me.wptCount);
|
||||||
|
}
|
||||||
|
|
||||||
if (coord != nil) {
|
var str = " <wpt>\n"
|
||||||
str ~= " <lat>" ~ coord.lat() ~ "</lat>\n";
|
~ " <name>" ~ wpt.name ~ "</name>\n";
|
||||||
str ~= " <lon>" ~ coord.lon() ~ "</lon>\n";
|
|
||||||
|
if (wpt.coord != nil) {
|
||||||
|
str ~= " <lat>" ~ wpt.coord.lat() ~ "</lat>\n";
|
||||||
|
str ~= " <lon>" ~ wpt.coord.lon() ~ "</lon>\n";
|
||||||
str ~= " <!--\n"
|
str ~= " <!--\n"
|
||||||
~ " " ~ coord.lat() ~ "," ~ coord.lon() ~ "\n"
|
~ " " ~ wpt.coord.lat() ~ "," ~ wpt.coord.lon() ~ "\n"
|
||||||
~ " -->\n";
|
~ " -->\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alt != nil) {
|
if (wpt.alt != nil) {
|
||||||
# str ~= " <alt>" ~ alt ~ "</alt>\n";
|
str ~= " <alt>" ~ wpt.alt ~ "</alt>\n";
|
||||||
str ~= " <crossat>" ~ alt ~ "</crossat>\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ktas != nil) {
|
if (wpt.crossAt != nil) {
|
||||||
str ~= " <ktas>" ~ ktas ~ "</ktas>\n";
|
str ~= " <crossat>" ~ wpt.crossAt ~ "</crossat>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groundAir != nil) {
|
if (wpt.ktas != nil) {
|
||||||
var onGround = groundAir == "ground" ? "true" : "false";
|
str ~= " <ktas>" ~ wpt.ktas ~ "</ktas>\n";
|
||||||
str ~= " <on-ground>" ~ onGround ~ "</on-ground>\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sec != nil) {
|
if (wpt.onGround != nil) {
|
||||||
str ~= " <time-sec>" ~ sec ~ "</time-sec>\n";
|
str ~= " <on-ground>" ~ (wpt.onGround ? "true" : "false") ~ "</on-ground>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wpt.waitSec != nil) {
|
||||||
|
str ~= " <time-sec>" ~ wpt.waitSec ~ "</time-sec>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wpt.flapsDown != nil) {
|
||||||
|
str ~= " <flaps-down>" ~ (wpt.flapsDown ? "true" : "false") ~ "</flaps-down>\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wpt.gearDown != nil) {
|
||||||
|
str ~= " <gear-down>" ~ (wpt.gearDown ? "true" : "false") ~ "</gear-down>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
str ~= " </wpt>\n";
|
str ~= " </wpt>\n";
|
||||||
|
|
||||||
io.write(me.fpFileHandler, str);
|
io.write(me.fpFileHandler, str);
|
||||||
|
|
||||||
|
me.wptCount += 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
#
|
#
|
||||||
|
175
nasal/io/waypoint.nas
Normal file
175
nasal/io/waypoint.nas
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
#
|
||||||
|
# Aerotow Everywhere - Add-on for FlightGear
|
||||||
|
#
|
||||||
|
# Written and developer by Roman Ludwicki (PlayeRom, SP-ROM)
|
||||||
|
#
|
||||||
|
# Copyright (C) 2022 Roman Ludwicki
|
||||||
|
#
|
||||||
|
# Aerotow Everywhere is an Open Source project and it is licensed
|
||||||
|
# under the GNU Public License v3 (GPLv3)
|
||||||
|
#
|
||||||
|
|
||||||
|
#
|
||||||
|
# Class Waypoint represent the data of waypoint in the flight plan.
|
||||||
|
#
|
||||||
|
var Waypoint = {
|
||||||
|
#
|
||||||
|
# Constructor
|
||||||
|
#
|
||||||
|
new: func () {
|
||||||
|
var obj = { parents: [Waypoint] };
|
||||||
|
|
||||||
|
obj.name = nil; # Name of waypoint. Special names are: "WAIT", "END".
|
||||||
|
obj.coord = nil; # geo.Coord object
|
||||||
|
obj.alt = nil; # Altitude AMSL in feet
|
||||||
|
obj.crossAt = nil; # Altitude AMSL in feet
|
||||||
|
obj.ktas = nil; # True airspeed in knots
|
||||||
|
obj.onGround = nil; # If true then on the ground, otherwise in air
|
||||||
|
obj.flapsDown = nil; # If true then flaps down, otherwise up
|
||||||
|
obj.gearDown = nil; # If true then gear down, otherwise up
|
||||||
|
obj.waitSec = nil; # Number of seconds for "WAIT" waypoint
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set name of waypoint
|
||||||
|
#
|
||||||
|
# name - Name of waypoint
|
||||||
|
#
|
||||||
|
setName: func (name) {
|
||||||
|
me.name = name;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set coordinates of waypoint
|
||||||
|
#
|
||||||
|
# coord - geo.Coord object
|
||||||
|
#
|
||||||
|
setCoord: func (coord) {
|
||||||
|
me.coord = coord;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set altitude in feet of waypoint
|
||||||
|
#
|
||||||
|
# alt - altitude in feet
|
||||||
|
#
|
||||||
|
setAlt: func (alt) {
|
||||||
|
me.alt = alt;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set altitude in feet of waypoint as cross at
|
||||||
|
#
|
||||||
|
# alt - altitude in feet
|
||||||
|
#
|
||||||
|
setCrossAt: func (crossAt) {
|
||||||
|
me.crossAt = crossAt;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set true airspeed in knots for waypoint
|
||||||
|
#
|
||||||
|
# ktas - true airspeed in knots
|
||||||
|
#
|
||||||
|
setKtas: func (ktas) {
|
||||||
|
me.ktas = ktas;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set waypoint on the ground
|
||||||
|
#
|
||||||
|
setOnGround: func () {
|
||||||
|
me.onGround = 1;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set flaps down
|
||||||
|
#
|
||||||
|
setFlapsDown: func () {
|
||||||
|
me.flapsDown = 1;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set gear down
|
||||||
|
#
|
||||||
|
setGearDown: func () {
|
||||||
|
me.gearDown = 1;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set number of seconds for WAIT waypoint. This force to use "WAIT" name.
|
||||||
|
#
|
||||||
|
# waitSec - Number of seconds
|
||||||
|
#
|
||||||
|
setWaitSec: func (waitSec) {
|
||||||
|
me.setName("WAIT"); # force WAIT name
|
||||||
|
me.waitSec = waitSec;
|
||||||
|
|
||||||
|
return me;
|
||||||
|
},
|
||||||
|
|
||||||
|
#
|
||||||
|
# Set all waypoint data from given hash object
|
||||||
|
#
|
||||||
|
setHashData: func (wptData) {
|
||||||
|
if (wptData == nil) {
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "name")) {
|
||||||
|
me.setName(wptData.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "coord")) {
|
||||||
|
me.setCoord(wptData.coord);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "crossAt")) {
|
||||||
|
me.setCrossAt(wptData.crossAt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "alt")) {
|
||||||
|
me.setAlt(wptData.alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "ktas")) {
|
||||||
|
me.setKtas(wptData.ktas);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "onGround") and wptData.onGround) {
|
||||||
|
me.setOnGround();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "flapsDown") and wptData.flapsDown) {
|
||||||
|
me.setFlapsDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "gearDown") and wptData.gearDown) {
|
||||||
|
me.setGearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contains(wptData, "waitSec")) {
|
||||||
|
me.setWaitSec(wptData.waitSec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return me;
|
||||||
|
}
|
||||||
|
};
|
@ -84,7 +84,7 @@ var Scenario = {
|
|||||||
"class": "aerotow-dragger",
|
"class": "aerotow-dragger",
|
||||||
"model": Aircraft.getSelected(me.addon).modelPath,
|
"model": Aircraft.getSelected(me.addon).modelPath,
|
||||||
"flightplan": FlightPlan.FILENAME_FLIGHTPLAN,
|
"flightplan": FlightPlan.FILENAME_FLIGHTPLAN,
|
||||||
"repeat": true, # start again indefinitely
|
"repeat": true, # start again indefinitely, it will work if the aircraft stops on the ground
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user