List of Nasal extension functions: Difference between revisions

Jump to navigation Jump to search
m
<syntaxhighlight>
m (→‎cmdarg(): remove duplicate link to message)
m (<syntaxhighlight>)
Line 15: Line 15:
As such, the cmdarg() function is primarily used for listener callbacks declared in XML markup, cmdarg() returns the listened-to property as props.Node object, so you can use it with all its methods (see [[$FG_ROOT]]/Nasal/props.nas) for example:
As such, the cmdarg() function is primarily used for listener callbacks declared in XML markup, cmdarg() returns the listened-to property as props.Node object, so you can use it with all its methods (see [[$FG_ROOT]]/Nasal/props.nas) for example:


  print(cmdarg().getPath(), " has been changed to ", cmdarg().getValue())
<syntaxhighlight lang="php">
print(cmdarg().getPath(), " has been changed to ", cmdarg().getValue())
</syntaxhighlight>


The cmdarg() function avoids that you have to type the exact same path twice (once here and once in the setlistener() command) and it makes clear that this is the listened to property. Also, you can use all the nice props.Node methods on cmdarg() directly:
The cmdarg() function avoids that you have to type the exact same path twice (once here and once in the setlistener() command) and it makes clear that this is the listened to property. Also, you can use all the nice props.Node methods on cmdarg() directly:


setlistener("/gear/launchbar/state", func {
<syntaxhighlight lang="php">
      if (cmdarg().getValue() == "Engaged")
setlistener("/gear/launchbar/state", func {
          setprop("/sim/messages/copilot", "Engaged!");
    if (cmdarg().getValue() == "Engaged")
  }, 1, 0);
        setprop("/sim/messages/copilot", "Engaged!");
}, 1, 0);
</syntaxhighlight>


Use of cmdarg() outside of XML-bindings won't cause an error, but (still) return the last cmdarg() property. This just won't be the listened-to property anymore, but whatever the last legitimate cmdarg() user set. Most of the time it will be the property root of a joystick binding.
Use of cmdarg() outside of XML-bindings won't cause an error, but (still) return the last cmdarg() property. This just won't be the listened-to property anymore, but whatever the last legitimate cmdarg() user set. Most of the time it will be the property root of a joystick binding.
Line 58: Line 62:
Concatenates an arbitrary number of arguments to one string, appends a new-line, and prints it to the terminal. Returns the number of printed characters.
Concatenates an arbitrary number of arguments to one string, appends a new-line, and prints it to the terminal. Returns the number of printed characters.


print("Just", " a ", "test");
<syntaxhighlight lang="php">
print("Just", " a ", "test");
</syntaxhighlight>


=== <tt>logprint()</tt> ===
=== <tt>logprint()</tt> ===
Line 67: Line 73:
Returns the node value for a given path, or <tt>nil</tt> if the node doesn't exist or hasn't been initialized yet.  
Returns the node value for a given path, or <tt>nil</tt> if the node doesn't exist or hasn't been initialized yet.  


getprop(<path>);
<syntaxhighlight lang="php">
getprop(<path>);
</syntaxhighlight>


Example:
Example:


print("The frame rate is ", getprop("/sim/frame-rate"), " FPS");
<syntaxhighlight lang="php">
 
print("The frame rate is ", getprop("/sim/frame-rate"), " FPS");
</syntaxhighlight>




Line 78: Line 87:
Sets a property value for a given node path string. Always returns nil.
Sets a property value for a given node path string. Always returns nil.


setprop(<path> [, <path>, [...]], <value>);
<syntaxhighlight lang="php">
setprop(<path> [, <path>, [...]], <value>);
</syntaxhighlight>


All arguments but the last are concatenated to a path string, with a slash (/) inserted between each element. The last value is written to the respective node. If the node isn't writable, then an error message is printed to the console.
All arguments but the last are concatenated to a path string, with a slash (/) inserted between each element. The last value is written to the respective node. If the node isn't writable, then an error message is printed to the console.
Line 84: Line 95:
Note: <tt>setprop()</tt> concatenates a list of input arguments by means of inserting a "/" in between. That is nice for properties, as this slash is part of the tree. However, when one wants to make use of indices, like [0], one has to concatenate by hand (using "~") ''inside'' one part of the string argument list. An example is:
Note: <tt>setprop()</tt> concatenates a list of input arguments by means of inserting a "/" in between. That is nice for properties, as this slash is part of the tree. However, when one wants to make use of indices, like [0], one has to concatenate by hand (using "~") ''inside'' one part of the string argument list. An example is:


  var i = 4;
<syntaxhighlight lang="php">
  setprop("instrumentation","cdu","page["~i~"]","title","MENU");
var i = 4;
setprop("instrumentation","cdu","page["~i~"]","title","MENU");
</syntaxhighlight>


This results in instrumentation/cdu/page[4]/title = 'MENU' (string)
This results in instrumentation/cdu/page[4]/title = 'MENU' (string)
Line 91: Line 104:
Examples:
Examples:


setprop("/sim/current-view/view-number", 2);
<syntaxhighlight lang="php">
setprop("/controls", "engines/engine[0]", "reverser", 1);
setprop("/sim/current-view/view-number", 2);
 
setprop("/controls", "engines/engine[0]", "reverser", 1);
</syntaxhighlight>


'''Erasing a property from the property tree''': a property that has been created, for example through <tt>setprop()</tt> can be erased via
'''Erasing a property from the property tree''': a property that has been created, for example through <tt>setprop()</tt> can be erased via


  props.globals.getNode("foo/bar").remove(); # take out the complete node
<syntaxhighlight lang="php">
  props.globals.getNode("/foo").removeChild("bar"); # take out a certain child node
props.globals.getNode("foo/bar").remove(); # take out the complete node
props.globals.getNode("/foo").removeChild("bar"); # take out a certain child node
</syntaxhighlight>


=== <tt>interpolate()</tt> ===
=== <tt>interpolate()</tt> ===
Give the value from a value or a source node to a destination node in given time.
Give the value from a value or a source node to a destination node in given time.


  interpolate(<path>, <value>, <time>);
<syntaxhighlight lang="php">
interpolate(<path>, <value>, <time>);


Examples:
Examples:
  interpolate("controls/switches/nav-lights-pos", 1, 0.25); # After 25ms, nav-lights-pos = 1
<syntaxhighlight lang="php">
  interpolate("controls/gear/brake-left-pos", getprop("controls/gear/brake-left"), 1); # After 1s, brake-left-pos = brake-left
interpolate("controls/switches/nav-lights-pos", 1, 0.25); # After 25ms, nav-lights-pos = 1
interpolate("controls/gear/brake-left-pos", getprop("controls/gear/brake-left"), 1); # After 1s, brake-left-pos = brake-left
</syntaxhighlight>


=== <tt>settimer()</tt> ===
=== <tt>settimer()</tt> ===
Runs a function after a given simulation time (default) or real time in seconds.
Runs a function after a given simulation time (default) or real time in seconds.


settimer(<function>, <time> [, <realtime=0>]);
<syntaxhighlight lang="php">
settimer(<function>, <time> [, <realtime=0>]);
</syntaxhighlight>


The first object is a function object (ie, "func { ... }").  Note that this is different from a function call (ie, "func ( ... )"). If you don't understand what this means, just remember to always enclose the first argument in any call to settimer with the word "func" and braces "{ }", and it will always work. For instance, if you want print the words "My result" in five seconds, use this code:
The first object is a function object (ie, "func { ... }").  Note that this is different from a function call (ie, "func ( ... )"). If you don't understand what this means, just remember to always enclose the first argument in any call to settimer with the word "func" and braces "{ }", and it will always work. For instance, if you want print the words "My result" in five seconds, use this code:


settimer ( func { print ( "My result"); }, 5);
<syntaxhighlight lang="php">
settimer ( func { print ( "My result"); }, 5);
</syntaxhighlight>


Inside the braces of the func object you can put any valid Nasal code, including a function call.  In fact, if you want to call a function with certain values as arguments, the way to do it is to turn it into a function object by enclosing it with a func{}, for example:
Inside the braces of the func object you can put any valid Nasal code, including a function call.  In fact, if you want to call a function with certain values as arguments, the way to do it is to turn it into a function object by enclosing it with a func{}, for example:


myarg1="My favorite string";
<syntaxhighlight lang="php">
myarg2=432;
myarg1="My favorite string";
settimer ( func { myfunction ( myarg1, myarg2); }, 25);
myarg2=432;
settimer ( func { myfunction ( myarg1, myarg2); }, 25);
</syntaxhighlight>


The third argument is optional and defaults to 0, which lets the time argument be interpreted as "seconds simulation time". In this case the timer doesn't run when FlightGear is paused. For user interaction purposes (measuring key press time, displaying popups, etc.) one usually prefers real time.
The third argument is optional and defaults to 0, which lets the time argument be interpreted as "seconds simulation time". In this case the timer doesn't run when FlightGear is paused. For user interaction purposes (measuring key press time, displaying popups, etc.) one usually prefers real time.


# simulation time example
<syntaxhighlight lang="php">
var copilot_annoyed = func { setprop("/sim/messages/copilot", "Stop it! Immediately!") }
# simulation time example
settimer(copilot_annoyed, 10);
var copilot_annoyed = func { setprop("/sim/messages/copilot", "Stop it! Immediately!") }
settimer(copilot_annoyed, 10);
</syntaxhighlight>
 
<syntaxhighlight lang="php">
# real time example
var popdown = func ( tipArg ) {
    fgcommand("dialog-close", tipArg);
}


# real time example
var selfStatusPopupTip = func (label, delay = 10, override = nil) {
var popdown = func ( tipArg ) {
  fgcommand("dialog-close", tipArg);
}
var selfStatusPopupTip = func (label, delay = 10, override = nil) {
     var tmpl = props.Node.new({
     var tmpl = props.Node.new({
             name : "PopTipSelf", modal : 0, layout : "hbox",
             name : "PopTipSelf", modal : 0, layout : "hbox",
Line 142: Line 170:
     });
     });
     if (override != nil) tmpl.setValues(override);
     if (override != nil) tmpl.setValues(override);
   
 
     popdown(tipArgSelf);
     popdown(tipArgSelf);
     fgcommand("dialog-new", tmpl);
     fgcommand("dialog-new", tmpl);
     fgcommand("dialog-show", tipArgSelf);
     fgcommand("dialog-show", tipArgSelf);
 
     currTimerSelf += 1;
     currTimerSelf += 1;
     var thisTimerSelf = currTimerSelf;
     var thisTimerSelf = currTimerSelf;
 
     # Final argument 1 is a flag to use "real" time, not simulated time
     # Final argument 1 is a flag to use "real" time, not simulated time
     settimer(func { if(currTimerSelf == thisTimerSelf) { popdown(tipArgSelf) } }, delay, 1);
     settimer(func { if(currTimerSelf == thisTimerSelf) { popdown(tipArgSelf) } }, delay, 1);
}
}
</syntaxhighlight>


[[Nasal scripting language#settimer loops|More information about using the settimer function to create loops.]]
[[Nasal scripting language#settimer loops|More information about using the settimer function to create loops.]]
Line 196: Line 225:
     m._hideTimer.singleShot = 1;
     m._hideTimer.singleShot = 1;


    return m;
  return m;
   },
   },
   run: func
   run: func
Line 213: Line 242:
Returns information about geodetic coordinates. Takes two arguments: lat, lon (in degree) and returns a vector with two entries, or nil if no information could be obtained because the terrain tile wasn't loaded. The first entry is the elevation (in meters) for the given point, and the second is a hash with information about the assigned material, or nil if there was no material information available, because there is, for instance, an untextured building at that spot or the scenery tile is not loaded.
Returns information about geodetic coordinates. Takes two arguments: lat, lon (in degree) and returns a vector with two entries, or nil if no information could be obtained because the terrain tile wasn't loaded. The first entry is the elevation (in meters) for the given point, and the second is a hash with information about the assigned material, or nil if there was no material information available, because there is, for instance, an untextured building at that spot or the scenery tile is not loaded.


var lat = getprop("/position/latitude-deg");
<syntaxhighlight lang="php">
var lon = getprop("/position/longitude-deg");
var lat = getprop("/position/latitude-deg");
var info = geodinfo(lat, lon);
var lon = getprop("/position/longitude-deg");
var info = geodinfo(lat, lon);
if (info != nil) {
 
    print("the terrain under the aircraft is at elevation ", info[0], " m");
if (info != nil) {
    if (info[1] != nil)
    print("the terrain under the aircraft is at elevation ", info[0], " m");
        print("and it is ", info[1].solid ? "solid ground" : "covered by water");
    if (info[1] != nil)
}
        print("and it is ", info[1].solid ? "solid ground" : "covered by water");
}
</syntaxhighlight>


A full data set looks like this:
A full data set looks like this:


debug.dump(geodinfo(lat, lon));
<syntaxhighlight lang="php">
debug.dump(geodinfo(lat, lon));
# outputs
 
[ 106.9892101062052, { light_coverage : 0, bumpiness : 0.5999999999999999, load_resistance : 1e+30,
# outputs
solid : 0,  names : [ "Lake", "Pond", "Reservoir", "Stream", "Canal" ], friction_factor : 1,  
[ 106.9892101062052, { light_coverage : 0, bumpiness : 0.5999999999999999, load_resistance : 1e+30,
rolling_friction : 1.5 } ]
solid : 0,  names : [ "Lake", "Pond", "Reservoir", "Stream", "Canal" ], friction_factor : 1,  
rolling_friction : 1.5 } ]
</syntaxhighlight>


Note that geodinfo is a *very* CPU intensive operation, particularly in FG 2.4.0 and earlier, so use sparingly ([http://flightgear.org/forums/viewtopic.php?f=4&p=135044#p135044 forum discussion here]).
Note that geodinfo is a *very* CPU intensive operation, particularly in FG 2.4.0 and earlier, so use sparingly ([http://flightgear.org/forums/viewtopic.php?f=4&p=135044#p135044 forum discussion here]).
Line 238: Line 271:
Usage:
Usage:


  var apt = airportinfo("KHAF");  # get info about KHAF
<syntaxhighlight lang="php">
  var apt = airportinfo(lat, lon); # get info about apt closest to lat/lon
var apt = airportinfo("KHAF");  # get info about KHAF
  var apt = airportinfo();        # get info about apt closest to aircraft   
var apt = airportinfo(lat, lon); # get info about apt closest to lat/lon
var apt = airportinfo();        # get info about apt closest to aircraft   
</syntaxhighlight>


The command debug.dump(airportinfo("KHAF")) outputs this:
The command debug.dump(airportinfo("KHAF")) outputs this:


  { lon : -122.4962626410256, lat : 37.51343502564102, has_metar : 0,
<syntaxhighlight lang="php">
{ lon : -122.4962626410256, lat : 37.51343502564102, has_metar : 0,
   runways : { 12 : { stopway2 : 0, threshold1 : 232.5624,
   runways : { 12 : { stopway2 : 0, threshold1 : 232.5624,
   lon : -122.5010889999999, lat : 37.513831, stopway1 : 0, width : 45.72,
   lon : -122.5010889999999, lat : 37.513831, stopway1 : 0, width : 45.72,
   threshold2 : 232.5624, heading : 138.1199999999999, length : 1523.0856 } },
   threshold2 : 232.5624, heading : 138.1199999999999, length : 1523.0856 } },
   elevation : 20.42159999999999, id : "KHAF", name : "Half Moon Bay" }
   elevation : 20.42159999999999, id : "KHAF", name : "Half Moon Bay" }
</syntaxhighlight>


That is: a hash with elements lat/lon/elev/id/name/has_metar for the airport, and a hash with runways, each of which consists of lat/lon/length/width/heading/threshold[12]/stopway[12]. Only one side of each runway is listed -- the other can easily be deduced.
That is: a hash with elements lat/lon/elev/id/name/has_metar for the airport, and a hash with runways, each of which consists of lat/lon/length/width/heading/threshold[12]/stopway[12]. Only one side of each runway is listed -- the other can easily be deduced.
Line 298: Line 335:


Usage:
Usage:
var fp = flightplan();
<syntaxhighlight lang="php">
var fp = flightplan('/some/path/to/a/flightplan.xml');
var fp = flightplan();
var fp = flightplan('/some/path/to/a/flightplan.xml');
</syntaxhighlight>


In advance of converting the Map and NavDisplay to use the [[Canvas]], James has improved the "flightplan()" extension function of the [[Nasal]] scripting interpreter to expose the full route-path vector for each flight plan leg as a vector on the leg.
In advance of converting the Map and NavDisplay to use the [[Canvas]], James has improved the "flightplan()" extension function of the [[Nasal]] scripting interpreter to expose the full route-path vector for each flight plan leg as a vector on the leg.
Line 316: Line 355:
Returns epoch time (time since 1972/01/01 00:00) in seconds as a floating point number with high resolution. This is useful for benchmarking purposes.
Returns epoch time (time since 1972/01/01 00:00) in seconds as a floating point number with high resolution. This is useful for benchmarking purposes.


  #benchmarking example:
<syntaxhighlight lang="php">
  var start = systime();
#benchmarking example:
  how_fast_am_I(123);
var start = systime();
  var end = systime();
how_fast_am_I(123);
  print("took ", end - start, " seconds");
var end = systime();
print("took ", end - start, " seconds");
</syntaxhighlight>


=== <tt>carttogeod()</tt> ===
=== <tt>carttogeod()</tt> ===
Converts cartesian coordinates x/y/z to geodetic coordinates lat/lon/alt, which are returned as a vector. Units are degree and meter.
Converts cartesian coordinates x/y/z to geodetic coordinates lat/lon/alt, which are returned as a vector. Units are degree and meter.


var geod = carttogeod(-2737504, -4264101, 3862172);
<syntaxhighlight lang="php">
print("lat=", geod[0], " lon=", geod[1], " alt=", geod[2]);
var geod = carttogeod(-2737504, -4264101, 3862172);
print("lat=", geod[0], " lon=", geod[1], " alt=", geod[2]);
# outputs
 
lat=37.49999782141546 lon=-122.6999914632327 alt=998.6042055172776
# outputs
lat=37.49999782141546 lon=-122.6999914632327 alt=998.6042055172776
</syntaxhighlight>


=== <tt>geodtocart()</tt> ===
=== <tt>geodtocart()</tt> ===
Converts geodetic coordinates lat/lon/alt to cartesian coordinates x/y/z. Units are degree and meter.
Converts geodetic coordinates lat/lon/alt to cartesian coordinates x/y/z. Units are degree and meter.


var cart = geodtocart(37.5, -122.7, 1000); # lat/lon/alt(m)
<syntaxhighlight lang="php">
print("x=", cart[0], " y=", cart[1], " z=", cart[2]);
var cart = geodtocart(37.5, -122.7, 1000); # lat/lon/alt(m)
print("x=", cart[0], " y=", cart[1], " z=", cart[2]);
# outputs
 
x=-2737504.667684828 y=-4264101.900993474 z=3862172.834656495
# outputs
x=-2737504.667684828 y=-4264101.900993474 z=3862172.834656495
</syntaxhighlight>


=== <tt>parsexml()</tt> ===
=== <tt>parsexml()</tt> ===
Line 344: Line 389:
This function is an interface to the built-in [http://expat.sourceforge.net/ Expat XML parser]. It takes up to five arguments. The first is a mandatory absolute path to an XML file, the remaining four are optional callback functions, each of which can be nil (which is also the default value).
This function is an interface to the built-in [http://expat.sourceforge.net/ Expat XML parser]. It takes up to five arguments. The first is a mandatory absolute path to an XML file, the remaining four are optional callback functions, each of which can be nil (which is also the default value).


<pre>
<syntaxhighlight lang="php">
var ret = parsexml(<path> [, <start-elem> [, <end-elem> [, <data> [, <pi> ]]]]);
var ret = parsexml(<path> [, <start-elem> [, <end-elem> [, <data> [, <pi> ]]]]);
 
<start-elem>  ... called for every starting tag with two arguments: the tag name, and an attribute hash
<start-elem>  ... called for every starting tag with two arguments: the tag name, and an attribute hash
<end-elem>    ... called for every ending tag with one argument: the tag name
<end-elem>    ... called for every ending tag with one argument: the tag name
<data>        ... called for every piece of data with one argument: the data string
<data>        ... called for every piece of data with one argument: the data string
<pi>          ... called for every "processing information" with two args: target and data string
<pi>          ... called for every "processing information" with two args: target and data string
 
<ret>        ... the return value is nil on error, and the <path> otherwise
<ret>        ... the return value is nil on error, and the <path> otherwise
</pre>
</syntaxhighlight>


Example:
Example:


<syntaxhighlight lang="php">
<syntaxhighlight lang="php">
var start = func(name, attr) {
var start = func(name, attr) {
    print("starting tag ", name);
    print("starting tag ", name);
    foreach (var a; keys(attr))
    foreach (var a; keys(attr))
        print("\twith attribute ", a, "=", attr[a]);
        print("\twith attribute ", a, "=", attr[a]);
}
}
var end = func(name) { print("ending tag ", name) }
var end = func(name) { print("ending tag ", name) }
var data = func(data) { print("data=", data) }
var data = func(data) { print("data=", data) }
var pi = func(target, data) { print("processing instruction: target=", target, " data=", data) }
var pi = func(target, data) { print("processing instruction: target=", target, " data=", data) }
parsexml("/tmp/foo.xml", start, end, data, pi);
parsexml("/tmp/foo.xml", start, end, data, pi);
</syntaxhighlight>
</syntaxhighlight>


395

edits

Navigation menu