284 lines
No EOL
7.1 KiB
Text
284 lines
No EOL
7.1 KiB
Text
# A3XX FMGC Waypoint database
|
|
# Copyright (c) 2023 Josh Davidson (Octal450) and Jonathan Redpath (legoboyvdlp)
|
|
|
|
var nilTree = {
|
|
"latitude": 0,
|
|
"longitude": 0,
|
|
"ident": "",
|
|
};
|
|
|
|
var WaypointDatabase = {
|
|
waypointsVec: [],
|
|
confirm: [0, 0],
|
|
# addWP - adds pilot waypoint to waypoints vector
|
|
# arg: wpObj - passed pilot waypoint object
|
|
# return:
|
|
# 0 - not allowed
|
|
# 2 - accepted
|
|
# 4 - database full
|
|
addWP: func(wpObj) {
|
|
# validate ghost
|
|
if (wpObj.wpGhost == nil) {
|
|
return 0;
|
|
}
|
|
|
|
# check size of database
|
|
if (me.getCount() >= 20) {
|
|
return 4;
|
|
}
|
|
|
|
if (wpObj.index >= me.getSize()) {
|
|
# add to end, since index doesn't exist
|
|
append(me.waypointsVec, wpObj);
|
|
me.write();
|
|
return 2;
|
|
} elsif (me.waypointsVec[wpObj.index] == nil) {
|
|
# add at passed index
|
|
me.waypointsVec[wpObj.index] = wpObj;
|
|
me.write();
|
|
return 2;
|
|
} else {
|
|
# fall back to end
|
|
logprint(4, "pilotWaypoint constructor claims index " ~ wpObj.index ~ " is nil, but it isn't!");
|
|
append(me.waypointsVec, wpObj);
|
|
me.write();
|
|
return 2;
|
|
}
|
|
|
|
},
|
|
# delete - empties waypoints vector
|
|
# callerIdx is the calling mcdu
|
|
delete: func(callerIdx) {
|
|
var noDel = 0;
|
|
for (var i = 0; i < me.getSize(); i = i + 1) {
|
|
if (me.waypointsVec[i] != nil) {
|
|
if (fmgc.flightPlanController.flightplans[2].indexOfWP(me.waypointsVec[i].wpGhost) == -1) { # docs says only checks active and secondary
|
|
me.waypointsVec[i] = nil;
|
|
}
|
|
}
|
|
}
|
|
me.write();
|
|
if (me.getCount() != 0) {
|
|
mcdu.mcdu_message(callerIdx, "PILOT ELEMENT RETAINED");
|
|
}
|
|
},
|
|
# deleteAtIndex - delete at specific index. Set to nil, so it still exists in vector
|
|
deleteAtIndex: func(index) {
|
|
if (index < 0 or index >= me.getSize() or index >= 20) {
|
|
return;
|
|
}
|
|
me.waypointsVec[index] = nil;
|
|
me.write();
|
|
},
|
|
# getNilIndex - find the first nil
|
|
# post 2020.1 use dedicated function vecindex()
|
|
getNilIndex: func() {
|
|
for (var i = 0; i < me.getSize(); i = i + 1) {
|
|
if (me.waypointsVec[i] == nil) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
},
|
|
# getNonNilIndex - find the first non-nil
|
|
# post 2020.1 use dedicated function vecindex()
|
|
getNonNilIndex: func() {
|
|
for (var i = 0; i < me.getSize(); i = i + 1) {
|
|
if (me.waypointsVec[i] != nil) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
},
|
|
# getNextFromIndex - find the next non-nil after a passed index
|
|
getNextFromIndex: func(index) {
|
|
for (var i = (index + 1); i < me.getSize(); i = i + 1) {
|
|
if (me.waypointsVec[i] != nil) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i <= index; i = i + 1) {
|
|
if (me.waypointsVec[i] != nil) {
|
|
return i;
|
|
}
|
|
}
|
|
return index;
|
|
},
|
|
# getPreviousFromIndex - find the next non-nil before a passed index
|
|
getPreviousFromIndex: func(index) {
|
|
for (var i = (index - 1); i >= 0; i = i - 1) {
|
|
if (me.waypointsVec[i] != nil) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
for (var i = (me.getSize() - 1); i >= index; i = i - 1) {
|
|
if (me.waypointsVec[i] != nil) {
|
|
return i;
|
|
}
|
|
}
|
|
return index;
|
|
},
|
|
# getNoOfIndex - return what number passed item is in list, neglecting "nil"
|
|
getNoOfIndex: func(index) {
|
|
var count = 0;
|
|
for (var i = 0; i <= index; i = i + 1) {
|
|
if (me.waypointsVec[i] == nil) {
|
|
continue;
|
|
}
|
|
count += 1;
|
|
}
|
|
return count;
|
|
},
|
|
# getCount - return size, neglecting "nil"
|
|
getCount: func() {
|
|
var count = 0;
|
|
for (var i = 0; i < me.getSize(); i = i + 1) {
|
|
if (me.waypointsVec[i] == nil) {
|
|
continue;
|
|
}
|
|
count += 1;
|
|
}
|
|
return count;
|
|
},
|
|
# getSize - return maximum size of vector
|
|
getSize: func() {
|
|
return size(me.waypointsVec);
|
|
},
|
|
# getWP - try to find waypoint whose name matches passed argument
|
|
getWP: func(text) {
|
|
for (var i = 0; i < me.getSize(); i = i + 1) {
|
|
if (me.waypointsVec[i] == nil) {
|
|
continue;
|
|
}
|
|
if (text == me.waypointsVec[i].wpGhost.wp_name) {
|
|
return me.waypointsVec[i].wpGhost;
|
|
}
|
|
}
|
|
return nil;
|
|
},
|
|
# write - write to file, as a hash structure
|
|
write: func() {
|
|
var path = pts.Sim.fgHome.getValue() ~ "/Export/A320SavedWaypoints.xml";
|
|
var tree = {
|
|
waypoints: {
|
|
|
|
},
|
|
};
|
|
|
|
for (var i = 0; i < me.getSize(); i = i + 1) {
|
|
if (me.waypointsVec[i] != nil) {
|
|
tree.waypoints["waypoint" ~ i] = me.waypointsVec[i].tree;
|
|
}
|
|
}
|
|
|
|
io.writexml(path, props.Node.new(tree)); # write the data
|
|
},
|
|
# read - read from a file, extract using props interface
|
|
read: func() {
|
|
var path = pts.Sim.fgHome.getValue() ~ "/Export/A320SavedWaypoints.xml";
|
|
# create file if it doesn't exist
|
|
if (io.stat(path) == nil) {
|
|
me.write();
|
|
return;
|
|
}
|
|
var data = io.readxml(path).getChild("waypoints");
|
|
var pilotWP = nil;
|
|
for (var i = 0; i < 20; i = i + 1) {
|
|
pilotWP = nil;
|
|
var childNode = data.getChild("waypoint" ~ i);
|
|
if (childNode == nil) {
|
|
continue;
|
|
}
|
|
|
|
var wpt = createWP({lat: num(childNode.getChild("latitude").getValue()), lon: num(childNode.getChild("longitude").getValue())},childNode.getChild("ident").getValue());
|
|
|
|
if (left(childNode.getChild("ident").getValue(), 3) == "PBD") {
|
|
pilotWP = pilotWaypoint.newAtPosition(wpt, "PBD", right(childNode.getChild("ident").getValue(), 1));
|
|
} else {
|
|
pilotWP = pilotWaypoint.newAtPosition(wpt, "LL", right(childNode.getChild("ident").getValue(), 1));
|
|
}
|
|
me.addWPToPos(pilotWP, right(childNode.getChild("ident").getValue(), 1));
|
|
}
|
|
},
|
|
# addWPToPos - helper for reading - inserts at specific index
|
|
# will create nil for intermediates
|
|
addWPToPos: func(wpObj, position) {
|
|
if (me.getSize() >= position) {
|
|
me.waypointsVec[position - 1] = wpObj;
|
|
} else {
|
|
var numToIns = position - me.getSize();
|
|
while (numToIns >= 1) {
|
|
append(me.waypointsVec, nil);
|
|
numToIns -= 1;
|
|
}
|
|
me.waypointsVec[position - 1] = wpObj;
|
|
}
|
|
},
|
|
};
|
|
|
|
var pilotWaypoint = {
|
|
new: func(positioned, typeStr) {
|
|
var pilotWp = { parents:[pilotWaypoint] };
|
|
|
|
# Figure out what the first index is we can use
|
|
var nilIndex = WaypointDatabase.getNilIndex();
|
|
var position = nil;
|
|
|
|
if (nilIndex == -1) {
|
|
position = WaypointDatabase.getSize() + 1;
|
|
} else {
|
|
position = nilIndex + 1
|
|
}
|
|
|
|
pilotWp.setId(typeStr ~ sprintf("%s", position));
|
|
pilotWp.index = position - 1;
|
|
|
|
# set ghost to created waypoint
|
|
pilotWp.wpGhost = createWP(positioned, pilotWp.id);
|
|
|
|
pilotWp.tree = {
|
|
"latitude": pilotWp.wpGhost.wp_lat,
|
|
"longitude": pilotWp.wpGhost.wp_lon,
|
|
"ident": pilotWp.id,
|
|
};
|
|
|
|
return pilotWp;
|
|
},
|
|
newAtPosition: func(positioned, typeStr, position) {
|
|
var pilotWp = { parents:[pilotWaypoint] };
|
|
|
|
pilotWp.setId(typeStr ~ sprintf("%s", position));
|
|
pilotWp.index = position - 1;
|
|
|
|
# set ghost to created waypoint
|
|
pilotWp.wpGhost = positioned;
|
|
|
|
pilotWp.tree = {
|
|
"latitude": pilotWp.wpGhost.wp_lat,
|
|
"longitude": pilotWp.wpGhost.wp_lon,
|
|
"ident": pilotWp.id,
|
|
};
|
|
|
|
return pilotWp;
|
|
},
|
|
setId: func(id) {
|
|
if (typeof(id) == "scalar") { me.id = id; }
|
|
},
|
|
getId: func() {
|
|
if (me.id != nil) { return id; }
|
|
},
|
|
};
|
|
|
|
setlistener("/MCDU[0]/page", func() {
|
|
if (getprop("/MCDU[0]/page") != "PILOTWP" and getprop("/MCDU[0]/page") != "STATUS") {
|
|
WaypointDatabase.confirm[0] = 0;
|
|
}
|
|
}, 0, 0);
|
|
|
|
setlistener("/MCDU[1]/page", func() {
|
|
if (getprop("/MCDU[1]/page") != "PILOTWP" and getprop("/MCDU[1]/page") != "STATUS") {
|
|
WaypointDatabase.confirm[1] = 0;
|
|
}
|
|
}, 0, 0); |