--- A patch against the recent CVS version may be here: ./location-in-air.xml.diff ---
<?xml version="1.0"?>
<!--
For information on how to use this feature, see
Docs/README.location-in-air
-->
<PropertyList>
<name>location-in-air</name>
<layout>vbox</layout>
<halign>left</halign>
<nasal>
<open>
me = "/sim/gui/dialogs/location-in-air";
magvar = getprop("/environment/magnetic-variation-deg");
mynode = props.globals.getNode(me, 1);
mode = {
"airport-btn": mynode.getNode("airport-btn", 1),
"lonlat-btn": mynode.getNode("lonlat-btn", 1),
"vor-btn": mynode.getNode("vor-btn", 1),
"ndb-btn": mynode.getNode("ndb-btn", 1),
"fix-btn": mynode.getNode("fix-btn", 1),
"ppos-btn": mynode.getNode("ppos-btn", 1),
};
# Function to push a radio button and clear all the others:
set_radio = func(m) {
foreach (k; keys(mode)) {
mode[k].setBoolValue(m == k);
}
}
initialized = 0;
foreach (k; keys(mode)) {
if (mode[k].getType() == "NONE") {
mode[k].setBoolValue(0);
}
initialized += mode[k].getBoolValue();
}
if (!initialized) {
set_radio("airport-btn");
}
# We need our own private variables, to have and to hold,
# without worrying about whether the FDM will mess with
# them. A subset of these will be copied to FDM variables
# with similar names. Which subset depends on which radio
# button is pushed.
myvars = {"airport-id" : 0, "runway" : 0,
"latitude-deg" : 4, "longitude-deg" : 4,
"vor-id" : 0, "ndb-id" : 0, "fix" : 0,
"offset-distance" : 0, "course-deg-mag" : 0,
"altitude-ft" : 0, "glideslope-deg" : 0,
"airspeed-kt" : 0, "heading-deg-mag" : 0,
};
# Inherit a few things from the fgfs command line:
if (!getprop(me, "did1")) {
setprop(me, "did1", 1); # inherit only once
foreach (varname ; keys(myvars)) {
nnn = props.globals.getNode("/sim/presets/" ~ varname, 1);
ttt = nnn.getType();
value = nnn.getValue();
# The reason for the following "if" is to make
# sure we assign a /string/ (not a numeric) to
# our copy of the variable.
# The reason for that is so that (later) we can distinguish
# between "" (which means take the default)
# and zero (which means the user wants a value of zero).
if (ttt == "STRING") {
setprop(me, varname, nnn.getValue());
} elsif (value != nil) {
# must be some kind of numeric
fmt = sprintf("%%1.%df", myvars[varname]);
setprop(me, varname, sprintf(fmt, nnn.getValue()));
} else {
setprop(me, varname, "");
}
}
# Now fix up a few of the inherited values,
# taking care of special cases:
# Relocating to surface doesn't make sense;
# we are supposed to be relocating aloft:
alt = getprop("/sim/presets/altitude-ft");
if (alt == -9999) {
alt = "";
} # else default to "inherited" reset-to-air altitude
setprop(me, "altitude-ft", alt);
# Inherit preset airspeed from command line:
ktas = getprop("/sim/presets/airspeed-kt");
if (ktas == 0) {
ktas = "";
}
setprop(me, "airspeed-kt", ktas);
# Probably never a good idea to inherit a heading;
# instead use current heading as the default.
if (1) {
setprop(me, "heading-deg-mag", "");
} else {
# Preset heading from command line was treated as
# /true/ heading; we want the corresponding
# /magnetic/ heading:
hdg = getprop("/sim/presets/heading-deg");
setprop(me, "heading-deg-mag", sprintf("%d", hdg - magvar));
}
} # end inheriting things
setprop(me, "altitude-agl-ft",
sprintf("%5.2f", getprop("/position/altitude-agl-ft")));
copycontrol = func(vvv, factor){
setprop(me, vvv,
sprintf("%5.2f", factor * getprop("/controls/flight", vvv)));
}
copycontrol("aileron", 1);
copycontrol("aileron-trim", 1);
copycontrol("elevator", -1);
copycontrol("elevator-trim", -1);
copycontrol("rudder", 1);
copycontrol("rudder-trim", 1);
# The rule is, if it doesn't say "mag" in the name, it
# is a true bearing, not a magnetic bearing.
# Like the FDM, we do as much as possible with true
# bearings internally.
# When displaying magnetic bearings to a user,
# convert them /immediately/ beforehand to magnetic
# by subtracting magvar.
# Similarly, when getting magnetic bearings from the user,
# convert them /immediately/ afterward to true
# by adding magvar.
hdg1 = getprop("/orientation/heading-deg");
setprop(me, "this-heading-deg-mag", sprintf("%d", hdg1 - magvar));
setprop(me, "this-throttle", sprintf("%5.2f",
getprop("/controls/engines/engine/throttle")));
setprop(me, "this-latitude-deg",
sprintf("%1.4f", getprop("/position/latitude-deg")));
setprop(me, "this-longitude-deg",
sprintf("%1.4f", getprop("/position/longitude-deg")));
</open>
<close> # just kept for educational purposes :-)
# Note that I would like to use the degree /symbol/
# rather than spelling out "deg" in the dialog labels.
# The utf-8 for this symbol is (°).
# However, alas, putting that into the label produces
# no visible result. Rumor suggests that we are using
# a font that doesn't have a glyph for this character.
</close>
</nasal>
<text>
<label>Location In Air</label>
</text>
<hrule><dummy/></hrule>
<text>
<label>Reference Point</label>
</text>
<group>
<layout>table</layout>
<halign>left</halign>
<radio>
<row>0</row><col>0</col>
<live>true</live>
<property>/sim/gui/dialogs/location-in-air/airport-btn</property>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>nasal</command>
<script>set_radio("airport-btn")</script>
</binding>
</radio>
<text>
<row>0</row><col>1</col>
<halign>left</halign>
<label>Airport:</label>
</text>
<input>
<row>0</row><col>2</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/airport-id</property>
</input>
<text>
<row>0</row><col>3</col>
<label>Runway:</label>
</text>
<input>
<row>0</row><col>4</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/runway</property>
</input>
<radio>
<row>1</row><col>0</col>
<live>true</live>
<property>/sim/gui/dialogs/location-in-air/lonlat-btn</property>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>nasal</command>
<script>set_radio("lonlat-btn")</script>
</binding>
</radio>
<text>
<row>1</row><col>1</col>
<halign>left</halign>
<label>Latitude:</label>
</text>
<input>
<row>1</row><col>2</col>
<pref-width>130</pref-width>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/latitude-deg</property>
</input>
<text>
<row>1</row><col>3</col>
<halign>left</halign>
<label>Longitude:</label>
</text>
<input>
<row>1</row><col>4</col>
<pref-width>130</pref-width>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/longitude-deg</property>
</input>
<radio>
<row>2</row><col>0</col>
<live>true</live>
<property>/sim/gui/dialogs/location-in-air/vor-btn</property>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>nasal</command>
<script>set_radio("vor-btn")</script>
</binding>
</radio>
<text>
<row>2</row><col>1</col>
<halign>left</halign>
<label>VOR:</label>
</text>
<input>
<row>2</row><col>2</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/vor-id</property>
</input>
<radio>
<row>3</row><col>0</col>
<live>true</live>
<property>/sim/gui/dialogs/location-in-air/ndb-btn</property>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>nasal</command>
<script>set_radio("ndb-btn")</script>
</binding>
</radio>
<text>
<row>3</row><col>1</col>
<halign>left</halign>
<label>NDB:</label>
</text>
<input>
<row>3</row><col>2</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/ndb-id</property>
</input>
<text>
<row>3</row><col>3</col>
<halign>left</halign>
<label>(3-letter ID)</label>
</text>
<radio>
<row>4</row><col>0</col>
<live>true</live>
<property>/sim/gui/dialogs/location-in-air/fix-btn</property>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>nasal</command>
<script>set_radio("fix-btn")</script>
</binding>
</radio>
<text>
<row>4</row><col>1</col>
<halign>left</halign>
<label>Waypoint:</label>
</text>
<input>
<row>4</row><col>2</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/fix</property>
</input>
<text>
<row>4</row><col>3</col>
<halign>left</halign>
<label>(5-character ID)</label>
</text>
<radio>
<row>5</row><col>0</col>
<live>true</live>
<property>/sim/gui/dialogs/location-in-air/ppos-btn</property>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>nasal</command>
<script>set_radio("ppos-btn")</script>
</binding>
</radio>
<text>
<row>5</row><col>1</col>
<halign>left</halign>
<label>Here</label>
</text>
<text>
<row>5</row><col>2</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/this-latitude-deg</property>
</text>
<text>
<row>5</row><col>4</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/this-longitude-deg</property>
</text>
</group>
<text>
<label>Offset from Reference Point</label>
</text>
<group>
<layout>table</layout>
<text>
<row>0</row><col>0</col>
<halign>right</halign>
<label>Distance:</label>
</text>
<input>
<row>0</row><col>1</col>
<property>/sim/gui/dialogs/location-in-air/offset-distance</property>
</input>
<text>
<row>0</row><col>2</col>
<halign>left</halign>
<label>nm </label>
</text>
<text>
<row>0</row><col>3</col>
<halign>right</halign>
<label>Course:</label>
</text>
<input>
<row>0</row><col>4</col>
<property>/sim/gui/dialogs/location-in-air/course-deg-mag</property>
</input>
<text>
<row>0</row><col>5</col>
<halign>left</halign>
<label>deg mag</label>
</text>
<text>
<row>1</row><col>2</col>
<halign>left</halign>
<label> </label>
</text>
<text>
<row>2</row><col>0</col>
<halign>right</halign>
<label>Altitude:</label>
</text>
<input>
<row>2</row><col>1</col>
<property>/sim/gui/dialogs/location-in-air/altitude-ft</property>
</input>
<text>
<row>2</row><col>2</col>
<halign>left</halign>
<label>ft MSL</label>
</text>
<text>
<row>2</row><col>3</col>
<halign>right</halign>
<label>Glideslope:</label>
</text>
<input>
<row>2</row><col>4</col>
<property>/sim/gui/dialogs/location-in-air/glideslope-deg</property>
</input>
<text>
<row>2</row><col>5</col>
<halign>left</halign>
<label>deg</label>
</text>
<text>
<row>3</row><col>0</col>
<halign>right</halign>
<label>Airspeed</label>
</text>
<input>
<row>3</row><col>1</col>
<property>/sim/gui/dialogs/location-in-air/airspeed-kt</property>
</input>
<text>
<row>3</row><col>2</col>
<halign>left</halign>
<label>kt</label>
</text>
<text>
<row>3</row><col>3</col>
<halign>right</halign>
<label>Heading:</label>
</text>
<input>
<row>3</row><col>4</col>
<property>/sim/gui/dialogs/location-in-air/heading-deg-mag</property>
</input>
<text>
<row>3</row><col>5</col>
<halign>left</halign>
<label>deg mag</label>
</text>
</group>
<group>
<layout>table</layout>
<text>
<row>0</row> <!-- blank row -->
</text>
<text>
<row>3</row><col>1</col>
<halign>left</halign>
<label>__pos__</label>
</text>
<text>
<row>3</row><col>2</col>
<halign>left</halign>
<label>__trim__</label>
</text>
<text>
<row>5</row><col>0</col>
<label>Aileron:</label>
</text>
<text>
<row>5</row><col>1</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/aileron</property>
</text>
<text>
<row>5</row><col>2</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/aileron-trim</property>
</text>
<text>
<row>5</row><col>3</col>
<halign>left</halign>
<label>+ = right</label>
</text>
<text>
<row>6</row><col>0</col>
<label>Elevator:</label>
</text>
<text>
<row>6</row><col>1</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/elevator</property>
</text>
<text>
<row>6</row><col>2</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/elevator-trim</property>
</text>
<text>
<row>6</row><col>3</col>
<halign>left</halign>
<label>+ = up</label>
</text>
<text>
<row>7</row><col>0</col>
<label>Rudder:</label>
</text>
<text>
<row>7</row><col>1</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/rudder</property>
</text>
<text>
<row>7</row><col>2</col>
<halign>left</halign>
<property>/sim/gui/dialogs/location-in-air/rudder-trim</property>
</text>
</group>
<group>
<layout>hbox</layout>
<default-padding>10</default-padding>
<button>
<legend>OK</legend>
<default>true</default>
<equal>true</equal>
<binding>
<command>dialog-apply</command>
</binding>
<binding>
<command>nasal</command>
<script> # bindings [13]
#props.dump(props.globals.getNode("/sim/presets"));
##### First, clear out all the FDM's variables:
foreach (varname ; keys(myvars)) {
setprop("/sim/presets", varname, "");
}
# Special treatment for some variables; they
# are numberic, not strings, so setting them to ""
# would be the same as zero, which would be in-range.
setprop("/sim/presets/longitude-deg", -9999);
setprop("/sim/presets/latitude-deg", -9999);
setprop("/sim/presets/altitude-ft", -9999);
# Special treatment for variables that are settable,
# but not part of our dialog:
setprop("/sim/presets/onground", 0);
setprop("/sim/presets/trim", 0);
setprop("/sim/presets/onground", 0);
#### Next, set the ones we care about
fixup = func(varname){
setprop("/sim/presets", varname, getprop(me, varname));
}
checkup = func(button, varname){
if (mode[button].getBoolValue()) {
fixup(varname);
}
}
checkup("airport-btn", "airport-id");
checkup("airport-btn", "runway");
checkup("lonlat-btn", "latitude-deg");
checkup("lonlat-btn", "longitude-deg");
checkup("vor-btn", "vor-id");
checkup("ndb-btn", "ndb-id");
checkup("fix-btn", "fix");
# implement "here" button i.e. present position:
if (mode["ppos-btn"].getBoolValue()) {
setprop("/sim/presets/latitude-deg",
getprop("/position/latitude-deg"));
setprop("/sim/presets/longitude-deg",
getprop("/position/longitude-deg"));
}
######
# now for the popup items that are /not/ connected to radio buttons:
# there should be six of them.
# I have no idea whether this does anything:
fixup("glideslope-deg");
# The distance from the reference point:
offset = getprop(me, "offset-distance");
# azimuth defaults to current heading
# otherwise convert from course == "degrees mag from"
# to azimuth == "degrees true to" to
magvar = getprop("/environment/magnetic-variation-deg");
az = getprop(me, "course-deg-mag");
if (az == "") {
az = getprop("/orientation/heading-deg");
} else {
az += magvar; # az now /true/ bearing
}
# Handle negative offsets;
# otherwise convert radial "from" to azimuth "to"
if (!offset){
offset = 0;
}
if (offset < 0) {
offset = - offset;
} else {
az += 180;
}
# Prettify the variable, in case anybody dumps it:
while (az > 360){
az -= 360;
}
setprop("/sim/presets/offset-azimuth", az);
setprop("/sim/presets/offset-distance", offset);
# altitude defaults to current altitude
alt = getprop(me, "altitude-ft");
if (alt == "") {
alt = getprop("/position/altitude-ft");
}
setprop("/sim/presets/altitude-ft", alt);
# airspeed defaults to current airspeed
ktas = getprop(me, "airspeed-kt");
if (ktas == "") {
ktas = getprop("/velocities/airspeed-kt");
}
setprop("/sim/presets/airspeed-kt", ktas);
# heading defaults to current heading
hdg_mag = getprop(me, "heading-deg-mag");
if (hdg_mag == "") {
# current heading was computed in the "open" section above:
hdg_mag = getprop(me, "this-heading-deg-mag");
}
setprop("/sim/presets/heading-deg", num(hdg_mag) + magvar);
setprop(me, "last-heading-deg-mag", hdg_mag);
# Save magneto, throttle, gear, trim, and view settings
# from the ravages of presets-commit.
xxx = props.globals.getNode("/controls/engines");
engs = xxx.getChildren("engine");
magvec = [];
thrvec = [];
setsize(magvec, size(engs));
setsize(thrvec, size(engs));
for(ii=0; ii < size(engs); ii=ii+1) {
magvec[ii] = engs[ii].getNode("magnetos", 1).getValue();
thrvec[ii] = engs[ii].getNode("throttle", 1).getValue();
}
atrim = getprop("/controls/flight/aileron-trim");
etrim = getprop("/controls/flight/elevator-trim");
rtrim = getprop("/controls/flight/rudder-trim");
gear_down = getprop("/controls/gear/gear-down");
view_field = getprop("/sim/current-view/field-of-view");
view_hdg = getprop("/sim/current-view/goal-heading-offset-deg");
view_pitch = getprop("/sim/current-view/goal-pitch-offset-deg");
#props.dump(props.globals.getNode("/sim/presets"));
</script>
</binding>
<binding>
<!-- vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv -->
<!-- This is a nasty thing; lots of brutal side-effects: -->
<command>presets-commit</command>
<!-- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -->
</binding>
<binding>
<command>nasal</command>
<script> <!-- binding [15] -->
# Restore magneto, throttle, view, and trim settings
# after the ravages of presets-commit.
lim = size(magvec); # same as size of thrvec
xxx = props.globals.getNode("/controls/engines");
engs = xxx.getChildren("engine");
for(ii=0; ii < lim; ii=ii+1) {
thismag = magvec[ii];
engs[ii].getNode("magnetos", 1).setValue(thismag);
# Throttle setting doesn't work in JSBSim
# (but works OK in larcsim):
engs[ii].getNode("throttle", 1).setValue(thrvec[ii]);
}
setprop("/controls/flight/aileron-trim", atrim);
setprop("/controls/flight/elevator-trim", etrim);
setprop("/controls/flight/rudder-trim", rtrim);
setprop("/controls/gear/gear-down", gear_down);
setprop("/sim/current-view/field-of-view", view_field);
setprop("/sim/current-view/goal-heading-offset-deg", view_hdg);
setprop("/sim/current-view/goal-pitch-offset-deg", view_pitch);
</script>
</binding>
<binding>
<command>dialog-close</command>
</binding>
</button>
<button>
<legend>Cancel</legend>
<equal>true</equal>
<key>Esc</key>
<binding>
<command>dialog-close</command>
</binding>
</button>
</group>
</PropertyList>