Nasal library
The FlightGear forum has a subforum related to: Nasal Scripting |
Nasal scripting |
---|
Nasal internals |
---|
Memory Management (GC) |
This page documents the global library functions and variables of FlightGear's built-in scripting language, Nasal. This includes core library functions, which were included in Nasal before its integration into FlightGear, the extension functions, which have been subsequently added, and are specifically designed for FlightGear, and the global variables, which are conversion variables, added with extension functions, for converting between units. The relevant folders in Git are:
All these functions and variables are in the global namespace, that is, they are directly accessible (e.g., one can call magvar()
instead of namespace.magvar()
). However, if a namespace must be used, globals
is the correct namespace, but using it is not recommended. For a more complete explanation, see Nasal Namespaces in-depth.
Tip Copy & paste the examples into your Nasal Console and execute them to see what they do. |
Core library functions
This is the list of the basic core library functions. Most of these functions were part of the original Nasal library (before its integration in to FlightGear), while some have been added or changed over time. See also:
append()
append(vector, element[, element[, ...]]);
This function appends, or adds, the given element(s) to the end of the vector given in the first argument. Returns the vector operated on.
- vector
- The vector to which the arguments will be appended.
- element
- An element to be added to the vector.
Examples
var vector = [1, 2, 3]; # Initialize the vector
append(vector, 4); # Append the number 4 to the end of the vector
debug.dump(vector); # Print the contents of the vector
var vector = [1, 2, 3]; # Initialize the vector
append(vector, 4, 5, 6); # Append the numbers 4, 5, and 6 to the end of the vector
debug.dump(vector); # Print the contents of the vector
bind()
bind(function, locals[, outer_scope]);
This creates a new function object. A function in Nasal is three things: the actual code, a hash/namespace of local variables available to the function namespace, and the closure object of that namespace. These correspond to the three arguments respectively.
- function
- Function to evaluate.
- locals
- Hash containing values that will become the namespace (first closure) for the function.
- outer_scope
- Optional function which is bound to the next closure. This can be bound to yet another, making a linked list.
Example
# This is a namespace/hash with a single member, named "key," which is initialized to 12
var Namespace = {
key: 12
};
# This is different namespace/hash containing a function
# dividing a variable "key" (which is unavailable/nil in this namespace) by 2
var AnotherNamespace = {
ret: func {
key /= 2;
}
};
# To see that key is not available, try to call AnotherNamespace.ret() first
call(AnotherNamespace.ret, [], nil, nil, var errors = []);
if(size(errors)){
print("Key could not be divided/resolved!");
debug.printerror(errors);
}
# Associate the AnotherNamespace.ret() function with the first namespace
# so that "key" is now available
var function = bind(AnotherNamespace.ret, Namespace);
# Invoke the new function
function();
# Print out the value of Namespace.key
# It was changed to 12 from 6 by AnotherNamespace.ret()
print(Namespace.key);
call()
call(func[, args[, me[, locals[, error]]]);
Calls the given function with the given arguments and returns the result. This function is very useful as it allows much more control over function calls and catches any errors or die()
calls that would normally trigger run-time errors cancelling execution of the script otherwise.
- func
- Function to execute.
- args
- Vector containing arguments to give to the called function.
- me
me
reference for the function call (i.e., for method calls). If given, this will override anyme
value existing in the namespace (locals argument).- locals
- A hash with key/value pairs that will be available to the called function, typically used as the namespace for the function to be called.
- error
- A vector to append errors to. If the called function generates an error, the error, place, and line will be written to this. These errors can be printed using
debug.printerror()
.
Examples
# prints "Called from call()"
call(func {
print("Called from call()");
});
# prints "a = 1 : b = 2
call(func(a, b){
print("a = ", a, " : b = ", b);
},
[1, 2]
);
var Hash = {
new: func {
var m = { parents: [Hash] };
m.el1 = "string1";
m.el2 = "string2";
return m;
}
};
# prints "me.el1 = string1", then "me.el2 = string2" on the next line
call(func(a, b){
print("me.el", a, " = ", me["el" ~ a]);
print("me.el", b, " = ", me["el" ~ b]);
},
[1, 2],
Hash.new()
);
# prints the value of math.pi
call(func {
print(pi);
}, nil, nil,
math
);
call(func {
print(math.ip); # math.ip doesn't exist
}, nil, nil, nil,
var errs = []
);
debug.printerror(errs); # The error is caught and printed using debug.printerror()
caller()
caller([level]);
Returns a vector containing a record from the current call stack. The level numbering starts from the currently executing function (level 0). Level 1 (the default) is the caller of the current function, and so on.
The result is a four-element vector containing [0] a hash of local variables, [1] the function object, [2] the full source file name (incl. path) and [3] the line number.
- level
- Optional integer specifying the stack level to return a result from. Defaults to 1 (i.e. the caller of the currently executing function).
Examples
var myFunction = func(a, b){
debug.dump(caller(0)[0]); # prints a hash of local variables, including arguments a and b
return 2 * 2;
};
print("2 x 2 = ", myFunction(2, 2));
var get_arg_value = func(){
print("Argument to myFunc = ", caller(1)[0]['a']); # print the value of myFunc's single argument, using caller()
};
var myFunc = func(a){
get_arg_value();
};
myFunc(3);
This is a real example taken from fgdata/Nasal/canvas/MapStructure.nas. Function r()
(above the TODOs) returns a hash with the key/value pairs as per its arguments. For example, something like this is returned: { name: "<name>", vis: 1, zindex: nil }
.
var MapStructure_selfTest = func() {
var temp = {};
temp.dlg = canvas.Window.new([600,400],"dialog");
temp.canvas = temp.dlg.createCanvas().setColorBackground(1,1,1,0.5);
temp.root = temp.canvas.createGroup();
var TestMap = temp.root.createChild("map");
TestMap.setController("Aircraft position");
TestMap.setRange(25); # TODO: implement zooming/panning via mouse/wheel here, for lack of buttons :-/
TestMap.setTranslation(
temp.canvas.get("view[0]")/2,
temp.canvas.get("view[1]")/2
);
var r = func(name,vis=1,zindex=nil) return caller(0)[0];
# TODO: we'll need some z-indexing here, right now it's just random
# TODO: use foreach/keys to show all layers in this case by traversing SymbolLayer.registry direclty ?
# maybe encode implicit z-indexing for each lcontroller ctor call ? - i.e. preferred above/below order ?
foreach(var type; [r('TFC',0),r('APT'),r('DME'),r('VOR'),r('NDB'),r('FIX',0),r('RTE'),r('WPT'),r('FLT'),r('WXR'),r('APS'), ] )
TestMap.addLayer(factory: canvas.SymbolLayer, type_arg: type.name,
visible: type.vis, priority: type.zindex,
);
}; # MapStructure_selfTest
chr()
chr(code);
Returns a character as per the single argument. Extended ASCII is supported (see http://www.asciitable.com/ for a list of supported characters), although this may vary between different systems. For a list of the most commonly used characters, see the ASCII printable code chart (Dec column). The following table lists supported control characters, along with their equivalent control characters in Nasal strings.
Note In Nasal, only strings enclosed with double-quotes ("string" ) supports control chracters. Strings in single quotes ('string' ) do not.
|
Code | Name | Equivalent to |
---|---|---|
10 | Newline | \n
|
9 | Horizontal tab | \t
|
13 | Carriage return | \r
|
- code
- Integer character code for the desired glyph.
Examples
print("Code 65 = ", chr(65)); # prints "Code 65 = A"
This example displays all of the characters in a list, in the format Code n = >char<
, n being the index, and char being the character.
for(var i = 0; i <= 255; i += 1){
print("Code ", i, " = >", chr(i), "<");
}
closure()
closure(func[, level]);
Returns the hash table containing the lexical namespace of the given function. The level numbering start with level 0 being the namespace of func.
- func
- Function to evaluate.
- level
- Optional integer specifying the scope level. Defaults to 0 (the namespace of func).
Example
var get_math_e = func {
return e; # return the value of math.e
}
var myFunction = bind(get_math_e, math); # bind get_math_e to the math namespace, so that math.e is immediately available to get_math_e
debug.dump(closure(myFunction)); # print the namespace of get_math_e
print(myFunction());
cmp()
cmp(a, b);
Compares two strings, returning -1 if a is less than b, 0 if they are identical and 1 if a is greater than b.
- a
- First string argument for comparison.
- b
- Second string argument for comparison.
Examples
print(cmp("1", "two")); # prints -1
print(cmp("string", "string")); # prints 0
print(cmp("one", "2")); # prints 1
print(cmp("string1", "string2")); # prints -1
compile()
compile(code[, filename]);
Compiles the specified code string and returns a function object bound to the current lexical context. If there is an error, the function dies, with the argument to die()
being filename.
- code
- String containing Nasal code to be compiled.
- filename
- Optional string used for error messages/logging. Defaults to
<compile>
Examples
var myCode = 'print("hello");';
var helloFunc = compile(myCode, "myCode");
helloFunc();
compile
is very convenient to support Nasal loaded from other files. For instance, PropertyList XML files (such as GUI dialogs) may contain embedded Nasal sections that need to be parsed, processed and compiled. For an example of how to do this, save the below XML code as $FG_ROOT/gui/dialogs/test.xml.
<?xml version="1.0"?>
<PropertyList>
<nasal><![CDATA[
print("You have FlightGear v", getprop("/sim/version/flightgear"));
]]></nasal>
</PropertyList>
Now, start FlightGear and execute this code in the Nasal Console.
# Build the path
var FGRoot = getprop("/sim/fg-root");
var filename = "/gui/dialogs/test.xml";
var path = FGRoot ~ filename;
var blob = io.read_properties(path);
var script = blob.getValues().nasal; # Get the nasal string
# Compile the script. We're passing the filename here for better runtime diagnostics
var code = call(func {
compile(script, filename);
}, nil, nil, var compilation_errors = []);
if(size(compilation_errors)){
die("Error compiling code in: " ~ filename);
}
# Invoke the compiled script, equivalent to code();
# We're using call() here to detect errors:
call(code, [], nil, nil, var runtime_errors = []);
if(size(runtime_errors)){
die("Error calling code compiled loaded from: " ~ filename);
}
contains()
contains(hash, key);
Returns 1 (True) if the hash contains the specified key, or 0 (False) if not.
- hash
- The hash to search in.
- key
- The scalar to be searched for, contained as a key in the hash.
Example
# Initialize a hash
var hash = {
element: "value"
};
print(contains(hash, "element") ? "Yes" : "No"); # This will print "Yes"
print(contains(hash, "element2") ? "Yes" : "No"); # This will print "No"
contains()
Note The feature documented below (Vector support) is only available as of SimGear commit ee39abbd3b70c9b6d5e3a1c4ccedddaac1a92b11 see MR #305 (fgdata) |
contains(vector, item);
Returns 1 (True) if the vector contains the specified item, or 0 (False) if not.
- vector
- The vector to search in.
- item
- The object to be searched for in the vector.
Example
# Initialize a vector
var vec = ["element", "foo"];
print(contains(vec, "element") ? "Yes" : "No"); # This will print "Yes"
print(contains(vec, "element2") ? "Yes" : "No"); # This will print "No"
delete()
delete(hash, key);
Deletes the key from the hash if it exists. Operationally, this is NOT identical to setting the hash value specified by the key to nil
as the key will stay in the hash (at least for a while). This variant potentially frees storage by deleting the reference to the key and by shrinking the hash. Returns the hash that has been operated on.
- hash
- The hash from which to delete the key.
- key
- The scalar to be deleted, contained as a key in the hash.
Example
# Initialize the hash
var hash = {
element1: "value1",
element2: "value2"
};
delete(hash, "element1"); # Delete element1
debug.dump(hash); # prints the hash, which is now minus element1
die()
die(error);
Terminates execution and unwinds the stack. The place and the line will be added to the error. This invokes the same internal exception handler used for internal runtime errors. Use this to signal fatal errors, or to implement exception handling. The error thrown (including internal runtime errors) can be caught with call()
.
- error
- String describing the error.
- Note This parameter is technically optional, but it is highly recommended to use it.
Example
print("Will print");
die("Don't go any further!");
print("Won't print"); # Will not be printed because die() stops the process
find()
find(needle, haystack);
Finds and returns the index of the first occurrence of the string needle in the string haystack, or -1 if no such occurrence was found.
- needle
- String to search for.
- haystack
- String to search in.
Examples
print(find("c", "abcdef")); # prints 2
print(find("x", "abcdef")); # prints -1
print(find("cd", "abcdef")); # prints 2
ghosttype()
ghosttype(ghost);
Returns a string containing either a descriptive name of a ghost (a raw C/C++ object), or a unique id (the pointer to the C/C++ naGhostType
instance) if no name has been set. Ghost is an acronym that stands for Garbage-collected Handle to OutSide Thingy.
- ghost
- Ghost to return a description for.
Example
print(ghosttype(airportinfo())); # prints "airport"
id()
id(object);
Returns a string containing information on the type and ID of the object provided in the single argument. The information is returned in the form of <type>:<id>
, where <type> is the type of object, and <id> is the ID.
- object
- Can be either of a string, a vector, a hash, a code, a function, or a ghost.
Example
print(id("A")); # prints "str:000000001624A590"
int()
int(number);
Returns the integer part of the numeric value of the single argument, or nil
if none exists.
- number
- Number or string with just a number in it to return an integer from.
Examples
print(int(23)); # prints "23"
print(int(23.123)); # prints "23"
debug.dump(int("string")); # prints "nil"
keys()
keys(hash);
Returns a vector containing the list of keys found in the single hash argument.
- hash
- The hash to return the keys from.
Example
# Initialize a hash
var hash = {
element1: "value",
element2: "value"
};
debug.dump(keys(hash)); # print the vector
left()
left(string, length);
Source — Version added: FG 2.12 (commit)
Returns a substring of string, starting from the left.
- string
- String to return part of.
- length
- Integer specifying the length of the substring to return.
Example
print(left("string", 2)); # prints "st"
num()
num(number);
Returns the numerical value of the single string argument, or nil
if none exists.
- number
- String with just a number in it to return a number from.
Examples
print(num("23")); # prints "23"
print(num("23.123")); # prints "23.123"
debug.dump(num("string")); # prints "nil"
pop()
pop(vector);
Removes and returns the last element of the single vector argument, or nil
if the vector is empty.
- vector
- Vector to remove an element from.
Examples
var vector = [1, 2, 3];
pop(vector);
debug.dump(vector); # prints "[1, 2]"
var vector = [1, 2, 3];
debug.dump(pop(vector)); # prints "3"
var vector = [];
debug.dump(pop(vector)); # prints "nil"
right()
right(string, length);
Source — Version added: FG 2.12 (commit)
Returns a substring of string, starting from the right.
- string
- String to return part of.
- length
- Integer specifying the length of the substring to return.
Example
print(right("string", 2)); # prints "ng"
setsize()
setsize(vector, size);
Sets the size of a vector. The first argument specifies a vector, the second a number representing the desired size of that vector. If the vector is currently larger than the specified size, it is truncated. If it is smaller, it is padded with nil
entries. Returns the vector operated upon.
- vector
- The vector to be operated on.
- size
- The desired size of the vector in number of entries.
Examples
var vector = [1, 2, 3]; # Initialize a vector
setsize(vector, 4);
debug.dump(vector); # print the vector
var vector = [1, 2, 3]; # Initialize a vector
setsize(vector, 2);
debug.dump(vector); # print the vector
size()
size(object);
Returns the size of the single argument. For strings, this is the length in bytes. For vectors, this is the number of elements. For hashes, it is the number of key/value pairs. If the argument is nil
or a number, this error will be thrown: object has no size()
.
- object
- Object to find the size of. Must be a string, a vector or a hash.
Examples
var string = "string";
print(size(string)); # prints "6"
var vector = [1, 2, 3];
print(size(vector)); # prints "3"
var hash = {
element1: "value1",
element2: "value2",
element3: "value3"
};
print(size(hash)); # prints "3"
sort()
sort(vector, function);
Returns a vector containing the elements in the input vector sorted in according to the rule given by function. Implemented with the ANSI C qsort()
, sort()
is stable. This means that if the rules in the first example are used, equal elements in the output vector will appear in the same relative order as they do in the input. It is run in a loop, so function is run several times.
- vector
- Input vector to sort.
- function
- Function according to which the elements will be sorted by. It should take two arguments and should return one of 1, 0, or -1.
Return value | Meaning |
---|---|
less than 0 | first argument should go before second argument |
0 | first argument equals second argument |
greater than 0 | first argument should go after second argument |
Examples
This example sorts elements from smallest to greatest.
var sort_rules = func(a, b){
if(a < b){
return -1; # A should before b in the returned vector
}elsif(a == b){
return 0; # A is equivalent to b
}else{
return 1; # A should after b in the returned vector
}
}
debug.dump(sort([3, 2, 5, 6, 4, 1], sort_rules)); # prints "[1, 2, 3, 4, 5, 6]"
This example sorts elements from greatest to smallest.
# Outputs the elements in reverse order (greatest to smallest)
var sort_rules = func(a, b){
if(a < b){
return 1; # -1 in the above example
}elsif(a == b){
return 0;
}else{
return -1; # 1 in the above example
}
}
debug.dump(sort([3, 2, 5, 6, 4, 1], sort_rules)); # prints "[6, 5, 4, 3, 2, 1]"
This example sorts a vector of strings (runways for example) from smallest to greatest.
var runways = ["09R","27R","26L","09L","15"];
var rwy = sort(runways,func(a,b) cmp(a,b));
debug.dump(rwy); # prints ['09L','09R','15','26L','27R']
split()
split(delimiter, string);
Splits the input string into a vector of substrings bounded by occurrences of the delimiter substring. See string.join().
- delimiter
- String that will split the substrings in the returned vector.
- string
- String to split up.
Examples
debug.dump(split("cd", "abcdef")); # prints "['ab', 'ef']"
debug.dump(split(".", "3.2.0")); # prints "[3, 2, 0]"
debug.dump(split("/", "path/to/file")); # prints "['path', 'to', 'file']"
sprintf()
sprintf(format[, arg[, arg, [...]]]);
Creates and returns a string formatted using ANSI C vsnprintf()
[1]. Below is a table of supported format specifiers.
Flags | |
---|---|
Flag | Output |
+ |
Forces to precede the result with a plus or minus sign (+ or -) even for positive numbers. By default, only negative numbers are preceded with a - sign. |
space | Prefixes non-signed numbers with a space. |
- |
Left-align the output of this placeholder (the default is to right-align the output) when the width option is specified. |
0 |
Use 0 instead of spaces to pad a field when the width option is specified. |
# |
Used with o , x or X specifiers the value is preceded with 0, 0x or 0X respectively for values different than zero. Used with e , E and f , it forces the written output to contain a decimal point even if no digits would follow. By default, if no digits follow, no decimal point is written. Used with g or G the result is the same as with e or E but trailing zeros are not removed.
|
Width | |
Integer specifying the minimum number of characters to be returned. This includes the decimal point and decimal fraction as well as + or - signs. | |
Precision | |
Integer preceded by a dot specifying the number of decimal places to be written. | |
Specifiers | |
Specifier | Output |
d , i |
Signed decimal number. |
s |
A string |
% |
Percent (%) character. |
c |
A single character assigned to a character code, the code given in an integer argument. See http://www.asciitable.com/ for a list of supported characters and their codes. |
o |
Unsigned integer as an octal number. |
u |
Unsigned decimal integer. |
x , X |
Unsigned integer as a hexadecimal number. If x is used, any letters in the number are lowercase, while X gives uppercase.
|
e , E |
Double value in scientific notation (i.e., [-]ddd.ddde[+/-]ddd), with an exponent being denoted by e or E depending on whether an upper or lowercase is used respectively. |
f |
Floating-point number, in fixed decimal notation, by default with 6 decimal places. |
F |
Appears to be available[2], but doesn't work. |
g , G |
Double in either normal or exponential notation, whichever is more appropriate for its magnitude. g uses lower-case letters, G uses upper-case letters. This type differs slightly from fixed-point notation in that insignificant zeroes to the right of the decimal point are not included. Also, the decimal point is not included on whole numbers.
|
- format
- String specifying the format. Can be used with or without a format specifiers. See below for examples.
- arg
- Argument specifying a value to replace a format placeholder (such as
%d
) in the format string. Not required if there are no format specifiers.
Examples
print(sprintf("%i", 54)); # prints "54"
print(sprintf("Pi = %+.10f", math.pi)); # prints "Pi = +3.1415926536"
print(sprintf("%6d", 23)); # prints " 23"
print(sprintf("%06d", 23)); # prints "000023"
var FGVer = getprop("/sim/version/flightgear");
print(sprintf("You have FlightGear v%s", FGVer)); # prints "You have FlightGear v<your version>"
print(sprintf("Hexadecimal 100000 = %X", 100000)); # prints "Hexadecimal 100000 = 186A0"
print(sprintf("Hexadecimal 100000 = %x", 100000)); # prints "Hexadecimal 100000 = 186a0"
print(sprintf("Code 65 is %c", 65)); # prints "Code 65 is A"
print(sprintf("%e", 54)); # prints "5.400000e+001"
print(sprintf("%E", 54)); # prints "5.400000E+001"
print(sprintf("%o", 54)); # prints "66"
print(sprintf("50%% of 100 is %i", 100 / 2)); # prints "50% of 100 is 50"
print(sprintf("%.2f", 1.4)); #prints "1.40"
print(sprintf("%.1f", 1.4)); #prints "1.4"
print(sprintf("% 4.1f", 1.4)); #prints " 1.4"
print(sprintf("%04.1f", 1.4)); #prints "01.4"
print(sprintf("% 6.1f", 1.4)); #prints " 1.4"
print(sprintf("%06.1f", 1.4)); #prints "0001.4"
streq()
streq(a, b);
Tests the string values of the two arguments for equality. This function is needed because the ==
operator (see Nasal Operators) tests for numeric equality first. If either or both the arguments are not strings, 0 (False) will be returned. Returns either 0 (False) or 1 (True).
Note This function is rarely required in typical code. |
- a
- First argument for testing equality.
- b
- Second argument for testing equality.
Examples
print(streq("0", "0")); # prints "1" (True)
print(0 == 0.0); # prints "1" (True)
print(streq("0", "0.0")); # prints "0" (False)
substr()
substr(string, start [, length]);
Similar the subvec()
, but operates on strings. Computes and returns a substring. The first argument specifies a string, the second is the index of the start of a substring, the optional third argument specifies a length (the default is to return the rest of the string from the start).
- string
- String to return a substring from.
- start
- Integer specifying the start of a substring. Negative values specify a position from the end of the string.
- length
- Optional argument specifying the length of the substring. Defaults to the end of the string.
Examples
print(substr("abcde", 1, 3)); # prints "bcd"
print(substr("abcde", 1)); # prints "bcde"
print(substr("abcde", 2, 1)); # prints "c"
print(substr("abcde", -2)); # prints "de"
print(substr("abcde", -3, 2)); # prints "cd"
subvec()
subvec(vector, start[, length]);
Returns a sub-range of a vector. The first argument specifies a vector, the second a starting index, and the optional third argument indicates a length (the default is to the end of the vector).
- vector
- The vector to take the sub-vector from.
- start
- The starting point of the sub-vector within the given vector.
- length
- Optional argument specifying the length of the sub-vector, from the starting point.
Notes:
- Omitting the vector and start arguments is not an error (possibly it should be) but the return value is nil.
- A negative start argument is an error. This seems wrong. Perhaps the language designer could comment.
- A value of start greater than size(vector) causes an error. A value equal to size(vector) returns an empty vector.
- If the value of length is greater than size(vector) - start then it is ignored. That is, all elements from start to the end of vector are returned. If length is zero then an empty vector is returned. A negative value of length causes an error.
Examples
var vector = [1, 2, 3];
debug.dump(subvec(vector, 0)); # prints "[1, 2, 3]"
var vector = [1, 2, 3];
debug.dump(subvec(vector, 1)); # prints "[2, 3]"
var vector = [1, 2, 3];
debug.dump(subvec(vector, 1, 1)); # prints "[2]"
typeof()
typeof(object);
Returns a string indicating the whether the object is nil
, a scalar (number or string), a vector, a hash, a function, or a ghost.
- object
- Object to return the type of.
Examples
var object = nil;
print(typeof(object)); # prints "nil"
var object = "Hello world!";
print(typeof(object)); # prints "scalar"
var object = math.pi;
print(typeof(object)); # prints "scalar"
var object = [1, 2, 3];
print(typeof(object)); # prints "vector"
var object = {};
print(typeof(object)); # prints "hash"
var object = func {};
print(typeof(object)); # prints "func"
var object = airportinfo();
print(typeof(object)); # prints "ghost"
Extension functions
The extension functions are global functions that have been added to Nasal since its integration into FlightGear. Unlike the core library functions, they are generally specifically designed to interact directly with FlightGear. Extension functions come from three source files:
- flightgear/src/Scripting/NasalPositioned.cxx
- flightgear/src/Scripting/NasalSys.cxx
- fgdata/Nasal/globals.nas
abort()
abort();
This function is a wrapper for the C++ abort()
function. It simply aborts FlightGear with an error, which varies depending on the operating system. This function should not really be used; instead, please use the "exit" fgcommand, which will exit FlightGear more gracefully (see example below).
Examples
This example will immediately stop FlightGear with an error, such as "FlightGear has stopped working."
abort();
For exiting FlightGear in a better way, please use the following code:
fgcommand("exit");
abs()
abs(number);
This simple function returns the absolute value of the provided number.
- number
- This argument is required and should be a number.
Examples
print(abs(1)); # prints "1"
print(abs(-1)); # prints "1"
aircraftToCart()
This new function in FG 2017.2.1 takes coordinates in aircraft structural coordinate system, and translate them into geocentric coordinates. Example for (5,6,7):
var pos = aircraftToCart({x: -5, y: 6, z: -7});
var coord = geo.Coord.new();
coord.set_xyz(pos.x, pos.y, pos.z);
Notice: x and z is inverted sign on purpose. if you want lat. lon, alt from that, just call: (degrees and meters)
coord.lat()
coord.lon()
coord.alt()
addcommand()
addcommand(name, code);
Source — Version added: FG 2.12 (commit)
This function enables the addition of a new custom fgcommand to FlightGear from within Nasal. An fgcommand created using this method can be used in exactly the same way as the built-in fgcommands. Also, an fgcommand created via this method will always return True or 1, like all other fgcommands.
- name
- This will become the name of the new fgcommand. Must be a string.
- code
- The code that will be executed when the fgcommand is run. Must be a function.
Examples
This example adds a new fgcommand and then runs it. Although it executes a simple print()
statement, any valid Nasal code can be used.
addcommand("myFGCmd", func(node) {
print("fgcommand 'myFGCmd' has been run.");
props.dump( node );
});
fgcommand("myFGCmd", props.Node.new({foo:1, bar:2}) );
This example demonstrates how parameters are defined in a new fgcommand.
addcommand("myFGCmd", func(node){
print(node.getNode("number").getValue()); # prints the value of "number," which is 12
});
fgcommand("myFGCmd", props.Node.new({"number": 12}));
airportinfo()
airportinfo();
airportinfo(type);
airportinfo(id);
airportinfo(lat, lon[, type]);
Function for retrieval of airport, heliport, or seaplane base information. It returns a Nasal ghost; however, its structure is like that of a Nasal hash. The following information is returned:
- parents: A vector containing a hash of various functions to access information about the runway. See flightgear/src/Scripting/NasalPositioned.cxx (line 2659) for full list.
- lon: Longitude of the location.
- lat: Latitude of the location.
- has_metar: True or false depending whether the airport has a METAR code defined for it.
- elevation: Elevation of the location in metres.
- id: ICAO code of the airport (or ID of the seaplane base/heliport).
- name: Name of the airport/heliport/seaplane base.
- runways
- <runway name>
- id: Name of runway.
- lat: Latitude of the runway.
- lon: Longitude of the runway.
- heading: Heading of the runway.
- length: Length of the runway in metres.
- width: Width of the runway in metres.
- surface: Runway surface type.
- threshold: Length of the runway's displaced threshold in metres. Will return 0 if there is none.
- stopway: Length of the runway's stopway (the area before the threshold) in metres. Will return 0 if there is none.
- reciprocal:
runway
ghost of the reciprocal runway. - ils_frequency_mhz: ILS frequency in megahertz.
- ils:
navaid
ghost of the ILS transmitter.
- <runway name>
- helipads
- <helipad name>
- id: Name of helipad.
- lat: Latitude of the helipad.
- lon: Longitude of the helipad.
- heading: Heading of the helipad.
- length: Length of the helipad in metres.
- width: Width of the helipad in metres.
- surface: Helipad surface type.
- <helipad name>
- taxiways
- <taxiway name>
- id: Name of taxiway.
- lat: Latitude of the taxiway.
- lon: Longitude of the taxiway.
- heading: Heading of the taxiway.
- length: Length of the taxiway in metres.
- width: Width of the taxiway in metres.
- surface: Taxiway surface type.
- <taxiway name>
Information is extracted in the same way as accessing members of a Nasal hash. For example:
# prints to lengths of the runways of the nearest airport in feet and metres
var info = airportinfo();
print("-- Lengths of the runways at ", info.name, " (", info.id, ") --");
foreach(var rwy; keys(info.runways)){
print(rwy, ": ", math.round(info.runways[rwy].length * M2FT), " ft (", info.runways[rwy].length, " m)");
}
Note that searches for locations that are a long way away (e.g., the nearest seaplane base to the middle of the Sahara) may cause FlightGear to pause for an amount of time.
- id
- The ICAO code of an airport to retrieve information about.
- type
- When this argument is used, the function will return the closest airport of a certain type. Can be one of "heliport," "seaport," or "airport" (default).
- Note Running this function without any parameters is equivalent to this:
airportinfo("airport");
- lat and lon
- When these parameters are used, the function will return information on the nearest airport, heliport or seaplane base (depending on the type parameter) to those coordinates.
Examples
var info = airportinfo();
print("Nearest airport: ", info.name, " (", info.id, ")"); # prints the name and ICAO code of the nearest airport
var info = airportinfo("heliport");
print("Elevation of the nearest heliport: ", math.round(info.elevation * M2FT), " ft"); # prints the elevation and name of the nearest heliport
var info = airportinfo("KSQL");
print("-- Runways of ", info.name, " (", info.id, "): --");
foreach(var rwy; keys(info.runways)) {
print(rwy); # prints the runways of KSQL
}
var info = airportinfo(37.81909385, -122.4722484);
print("Coordinates of the nearest airport: ", info.lat, ", ", info.lon); # print the name and ICAO of the nearest airport to the Golden Gate Bridge
var info = airportinfo(37.81909385, -122.4722484, "seaport");
print("Nearest seaplane base: ", info.name, " (", info.id, ")"); # print the name and ID of the nearest seaplane base to the Golden Gate Bridge
This example prints the all information from an airportinfo()
call.
var info = airportinfo("KSFO");
print(info.name);
print(info.id);
print(info.lat);
print(info.lon);
print(info.has_metar);
print(info.elevation);
foreach(var rwy; keys(info.runways)){
print("-- ", rwy, " --");
print(info.runways[rwy].lat);
print(info.runways[rwy].lon);
print(info.runways[rwy].length);
print(info.runways[rwy].width);
print(info.runways[rwy].heading);
print(info.runways[rwy].stopway);
print(info.runways[rwy].threshold);
}
airwaysRoute()
airwaysRoute(start, end[, type]);
This function returns a vector containing waypoints between two given waypoints. The returned waypoints are ghosts, but can be accessed in the same way as a Nasal hash. See Nasal Flightplan for more information.
- start
- Start waypoint, in the form of a waypoint ghost, such as that provided by
flightplan()
. - end
- Same as above.
- type
- Instructs the function to compute a high level route (when set to "highlevel"), or a low level route (when set to "lowlevel"). Defaults to "highlevel."
Examples
In the route manager dialog, add two waypoints to the flightplan, ideally ones that are far apart (tip: use the Map for this). Then run this code in your Nasal Console.
var fp = flightplan();
var start = fp.getWP(0);
var end = fp.getWP(fp.getPlanSize() - 1);
var rt = airwaysRoute(start, end);
foreach(var wp; rt){
print(wp.wp_name); # print the waypoints in the computed route
}
Exactly the same as above, but computes a low level path.
var fp = flightplan();
var start = fp.getWP(0);
var end = fp.getWP(fp.getPlanSize() - 1);
var rt = airwaysRoute(start, end, "lowlevel");
foreach(var wp; rt){
print(wp.wp_name); # print the waypoints in the computed route
}
airway()
airway(ident [, pos]);
This function returns a ghost containing an airway of a specified id.
- ident
- a Positioned ghost (leg, navaid, airport) and so on, passed to the search function.
- pos
assert()
assert(condition[, message]);
Source — Version added: FG 3.2 (commit)
Returns either true if the condition evaluates as true, or aborts with a die()
call, which can be customised.
- condition
- Condition to evaluate.
- message
- Optional message that will be used in any
die()
call. Defaults to "assertion failed!"
Examples
var a = 1;
var b = 2;
print(assert(a < b)); # prints "1" (true)
var a = 1;
var b = 2;
assert(a > b, 'a is not greater than b'); # aborts with a custom error message
carttogeod()
carttogeod(x, y, z);
Converts Earth-centered, Earth-fixed coordinates (x, y and z) to geodetic coordinates (latitude, longitude, and altitude). A vector is returned containing latitude and longitude, both in degrees, and altitude, which is returned in metres above the equatorial radius of Earth as defined by the WGS 84 (6,378,137 metres).[3]
- x
- Mandatory x-axis value, in metres.
- y
- Mandatory y-axis value, in metres.
- z
- Mandatory z-axis value, in metres.
Example
var (lat, lon, alt) = carttogeod(6378137, 0, 0); # point is the intersection of the prime meridian and equator.
print("Latitude: ", lat); # prints lat, lon and alt, which are all zero, see above
print("Longitude: ", lon);
print("Altitude: ", alt);
cmdarg()
- _cmdarg()
cmdarg();
cmdarg()
returns the property root of certain types of XML files. These could be nodes in the Property Tree, or temporary and/or non-public nodes outside the Property tree.
It is used by Nasal scripts embedded in XML files. It returns a props.Node
object (see fgdata/Nasal/props.nas), and you can use all of its methods on the returned value. cmdarg()
should only be used in four types/places of XML files:
- Bindings: This is needed so that the value of a joystick's axis can be accessed internally.
- Dialogs: This will return the root of the dialog in the Property Tree. This is useful for dialogs that are created/modified procedurally (e.g. for populating/changing widgets while loading the dialog).
- Embedded Canvases: The Nasal code behind Canvas windows embedded in PUI dialogs can use it to accessing the root directory of their Canvas.
- Animation XML files: If the animation XML file is used in an AI/MP model,
cmdarg()
will return the root of the AI model in the/ai/models/
directory. Examples:/ai/models/aircraft[3]/
,/ai/models/multiplayer[1]/
You should not use cmdarg()
in places other than those stated above. Although it won't cause an error, it will return the value of the last legitimate cmdarg()
call.
Also, you should not delay cmdarg()
using maketimer()
, settimer()
or setlistener()
, because it will return an unrelated property.
Example
This example demonstrates the usage of cmdarg()
in a binding. Save the below XML snippet as $FG_ROOT/gui/dialogs/cmdarg-demo.xml. Then run the Nasal snippet below in your Nasal Console. Upon clicking Close, a message will be printed sowing the root of the binding in the Property Tree.
<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
<name>cmdarg-demo</name>
<layout>vbox</layout>
<text>
<label>Click "Close" to activate the demonstration (a message in the console).</label>
</text>
<button>
<legend>Close</legend>
<binding>
<command>nasal</command>
<script>print("Button binding root: '" ~ cmdarg().getPath() ~ "'");</script>
</binding>
<binding>
<command>dialog-close</command>
</binding>
</button>
</PropertyList>
fgcommand("dialog-show", {"dialog-name": "cmdarg-demo"});
This example demonstrates the usage of cmdarg()
in Nasal code within dialogs. Open $FG_ROOT/gui/dialogs/cmdarg-demo.xml from the previous example, copy & paste the code below, and save it. Then run the same Nasal snippet as the previous example in your Nasal Console. If you click Click me!, the button's label will change to "I've been changed!"
<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
<name>cmdarg-demo</name>
<layout>vbox</layout>
<text>
<label>Click "Click me!" to activate the demonstration (the button's label will change).</label>
</text>
<button>
<legend>Click me!</legend>
<binding>
<command>nasal</command>
<script>change_label();</script>
</binding>
</button>
<button>
<legend>Close</legend>
<binding>
<command>dialog-close</command>
</binding>
</button>
<nasal>
<open><![CDATA[
var dlg_root = cmdarg();
var dlg_name = {"dialog-name": "cmdarg-demo"};
var change_label = func {
dlg_root.getNode("button[0]/legend").setValue("I've been changed!");
fgcommand("dialog-close", dlg_name);
fgcommand("dialog-show", dlg_name);
}
]]></open>
</nasal>
</PropertyList>
For an example of cmdarg()
used with Canvas, please see Howto:Adding a canvas to a GUI dialog.
courseAndDistance()
courseAndDistance(to);
courseAndDistance(from, to);
Returns a vector containing the course from one point to another and the distance between them in nautical miles. The course is the initial bearing (see here), and is in the range 0–360. Both arguments can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object with geodetic coordinates (cartesian coordinates will not be accepted)
- An
- from
- Optional parameter defining the from where the function should calculate its results. If the function is given one argument (to), the aircraft's current position will be used. As well as the argument types as defined above, this argument can be two numbers separated with a comma, as if the function is taking three arguments. See example 5 below.
- to
- Like the first parameter, but defines the second point.
Examples
This example demonstrates the usage of the function with the airport
ghost type.
var from = airportinfo("KSFO");
var to = airportinfo("KSQL");
var (course, dist) = courseAndDistance(from, to);
print(course); # prints course from KSFO to KSQL
print(dist); # prints distance in nm from KSFO to KSQL
This example demonstrates the usage of the function with hashes containing lat and lon.
var from = {lat: 0, lon: 0};
var to = {lat: 1, lon: 1};
var (course, dist) = courseAndDistance(from, to);
print(course);
print(dist);
This example demonstrates usage of a geo.Coord object.
var from = geo.Coord.new().set_latlon(0, 0);
var to = geo.Coord.new().set_latlon(1, 1);
var (course, dist) = courseAndDistance(from, to);
print(course);
print(dist);
This example demonstrates usage of differing parameter types.
var from = airportinfo("KSFO");
var to = geo.Coord.new().set_latlon(0, 0);
var (course, dist) = courseAndDistance(from, to);
print(course);
print(dist);
The same as above, but the other way round.
var to = {lat: 1, lon: 1};
var (course, dist) = courseAndDistance(0, 0, to);
print(course);
print(dist);
Usage of just one parameter.
var dest = airportinfo("KSQL");
var (course, dist) = courseAndDistance(dest);
print("Turn to heading ", math.round(course), ". You have ", sprintf("%.2f", dist), " nm to go");
createFlightplan()
createFlightplan(path);
Creates an empty flightplan object. It accepts one argument, path passed an absolute path to a .fgfp / .gpx file, it will populate the flightplan with waypoints from the file.
- path
- Optional parameter defining the file from which a flightplan will be populated.
Example
var path = getprop("/sim/fg-home") ~ "/Export/test.fgfp";
var flightplan = createFlightplan(path);
debug.dump(flightplan);
createDiscontinuity()
createDiscontinuity();
Source — Version added: FG 2016.1 (commit)
Returns a waypoint
ghost object. A route discontinuity is inserted by an FMS when it is unsure how to connect two waypoints.
createViaTo()
createViaTo(airway, waypoint);
Source — Version added: FG 2016.1 (commit)
Returns a waypoint
ghost object. It represents a route "via airway to waypoint".
- airway
- The name of an airway.
- waypoint
- Must be in the airway and one of:
- The name of a waypoint.
- An
airport
,navaid
,runway
, orfix
ghost object.
createWP()
createWP(pos, name[, flag]);
Creates a new waypoint ghost object.
- pos
- Dictates the position of the new waypoint. It can be one of the following:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object
- Two numbers separated by a comma, as if the function is taking three arguments. See example 4 below.
- An
- name
- String that will become the name of the new waypoint.
- flag
- Optional string that will tell FlightGear what type of waypoint it is. Must be one of "sid," "star," "approach," "missed," or "pseudo."
Examples
Creates a waypoint directly in front and 1 km away and appends it to the flight plan.
var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 1000);
var wp = createWP(pos, "NEWWP");
var fp = flightplan();
fp.appendWP(wp);
var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 1000);
var wp = createWP({lat: pos.lat(), lon: pos.lon()}, "NEWWP");
var fp = flightplan();
fp.appendWP(wp);
var apt = airportinfo();
var wp = createWP(apt, "NEWWP");
var fp = flightplan();
fp.appendWP(wp);
var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 1000);
var wp = createWP(pos.lat(), pos.lon(), "NEWWP");
var fp = flightplan();
fp.appendWP(wp);
Creates a new waypoint and adds it to the flight plan. Waypoints of the type "pseudo" are then removed from the flight plan, including the new waypoint. The print()
statements show this.
var pos = geo.aircraft_position().apply_course_distance(getprop("/orientation/heading-deg"), 1000);
var wp = createWP(pos, "NEWWP", "pseudo");
var fp = flightplan();
fp.appendWP(wp);
print(fp.getPlanSize());
fp.clearWPType("pseudo");
print(fp.getPlanSize());
createWPFrom()
createWPFrom(object[, flag]);
Creates a new waypoint object from another object.
- object
- A ghost object. Must be a ghost type that is one of "airport," "navaid," "runway," or "fix."
- flag
- Optional string that will tell FlightGear what type of waypoint it is. Must be one of "sid," "star," "approach," "missed," or "pseudo."
Examples
Creates a new waypoint and appends it to the flight plan.
var apt = airportinfo("KSFO");
var wp = createWPFrom(apt);
var fp = flightplan();
fp.appendWP(wp);
Creates a new waypoint and appends it to the flight plan. This way point is then removed; the print()
statements prove this.
var apt = airportinfo("KSFO");
var wp = createWPFrom(apt, "pseudo");
print(wp.wp_name);
var fp = flightplan();
fp.appendWP(wp);
print(fp.getPlanSize());
fp.clearWPType("pseudo");
print(fp.getPlanSize());
defined()
defined(symbol);
Returns 1 (true) or 0 (false) depending on whether a variable exists.
- symbol
- A string that will be what the function searches for.
Example
var number = 12;
var check_exist = func {
print("Variable 'number' ", defined("number") == 1 ? "exists" : "does not exist"); # 'number' does exist
print("Variable 'number2' ", defined("number2") == 1 ? "exists" : "does not exist"); # 'number2' does not exist
}
check_exist();
directory()
directory(path);
Returns a vector containing a list of the folders and files in a given file path or nil
if the path doesn't exist. Hidden folders and files are not added to the vector.
Note The first two elements of the vector will be '.'
and '..'
. These are for navigating back up the file tree, but have no use in Nasal. They can be safely removed from the vector.
- path
- Absolute file path.
Example
Gets the folders and files in $FG_ROOT, and then removes the extra first two elements (see note above).
var dir = directory(getprop("/sim/fg-root")); # get directory
dir = subvec(dir, 2); # strips off the first two elements
debug.dump(dir); # dump the vector
fgcommand()
fgcommand(cmd[, args]);
Runs an fgcommand. See also $FG_ROOT/Docs/README.commands and Bindings for more information. See flightgear/src/Main/fg_commands.cxx (line 1425) for the full list of fgcommands. Note that fgcommands generated by addcommand()
can also be run using this function. Also, the full list of fgcommands depends on the version of FlightGear you have. Returns 1 (true) if the fgcommand succeeded or 0 (false) if it failed.
- cmd
- String that is the name of the command that is to be run.
- args
- If the fgcommand takes arguments, they are inputted using this argument. Can either be a
props.Node
object, or a hash (see examples below).
Examples
fgcommand("null"); # does nothing
var args = props.Node.new({'script': 'print("Running fgcommand");'});
if (fgcommand("nasal", args)) { # prints "Running fgcommand" and then one of these print statements
print("Fgcommand succeeded");
} else {
print("Fgcommand encountered a problem");
}
var args = { 'dialog-name': 'about' };
fgcommand("dialog-show", args); # shows the 'about' dialog
findAirportsByICAO()
findAirportsByICAO(search[, type]);
Returns a vector containing airport
ghost objects which are (by default) airports whose ICAO code matches the search string. The results are sorted by range from closest to furthest.
- search
- Search string for the function. Can either be a partial or a full ICAO code.
- Caution The more matches there are for the given code, the longer the function will take. Passing just one character (e.g., "K"), might make FlightGear hang for a certain amount of time.
- type
- This will narrow the search to airports of a certain type. By default, only airports are searched for. May be one of "airport," "heliport," or "seaport."
Examples
var apts = findAirportsByICAO("KSF"); # finds all airports matching "KSF"
foreach(var apt; apts){
print(apt.name, " (", apt.id, ")"); # prints them
}
var apts = findAirportsByICAO("SP0", "seaport"); # finds all seaplane bases matching "SP0"
foreach(var apt; apts){
print(apt.name, " (", apt.id, ")"); # prints them
}
var apt = findAirportsByICAO("XBET"); # one way to check if an airport does exist"
if (size(apt) == 0) {
print("Airport does not exist"); # this one will be printed
} else {
print("Airport does exist");
}
findAirportsWithinRange()
findAirportsWithinRange([pos, ]range[, type]);
Returns a vector of airport
ghost object which are (by default) airports that are within a given range of a given position, or the aircraft's current position. The results are sorted by range from closest to furthest.
- pos
- Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object
- Two numbers separated by a comma, as if the function is taking three arguments. Example:
findAirportsWithinRange(lat, lon, range, type);
.
- An
- range
- Mandatory number giving the range in nautical miles within which to search for airports/heliports/seaplane bases.only airports are searched for.
- type
- This will narrow the search to airports of a certain type. By default, only airports are searched for. May be one of "airport," "heliport," or "seaport."
Examples
Searches for airports within 10 nm of KSFO.
var pos = airportinfo("KSFO");
var apts = findAirportsWithinRange(pos, 10);
foreach(var apt; apts){
print(apt.name, " (", apt.id, ")");
}
Searches for seaplane bases within 15 nm of KSFO.
var pos = airportinfo("KSFO");
var apts = findAirportsWithinRange(pos, 15, "seaport");
foreach(var apt; apts){
print(apt.name, " (", apt.id, ")");
}
Searches for airports within 10 nm of your current position.
var apts = findAirportsWithinRange(10);
foreach(var apt; apts){
print(apt.name, " (", apt.id, ")");
}
findCommByFrequencyMHz()
findCommByFrequencyMHz([pos, ]freq[, type]);
Returns a comm
ghost object for a station matching a given frequency. If there is more than one station with that frequency, the nearest station is returned.
pos
- Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object
- Two numbers separated by a comma, as if the function is taking three arguments. Example:
findCommByFrequencyMHz(lat, lon, freq, type);
.
- An
- freq
- Frequency, in megahertz, of the station to search for.
- type
- This will narrow the search to station of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 160)
Example
var com = findCommByFrequencyMHz(123.6); print("ID: ", com.id); # prints info about the comm station print("Name: ", com.name); print("Latitude: ", com.lat); print("Longitude: ", com.lon); print("Type: ", com.type); print("Frequency: ", sprintf("%.3f", com.frequency), " Mhz");
findFixesByID()
findFixesByID([pos, ]id);
Returns a vector containing fix
ghost objects matching a given ID, sorted by range from a certain position.
Note Fixes are (usually) also known as waypoints.
- pos
- Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object
- Two numbers separated by a comma, as if the function is taking three arguments. Example:
findFixesByID(lat, lon, id);
.
- An
- id
- Full or partial ID of the fix to search for.
- Note Inputting a partial ID does not work correctly (see here). It is best to just input a full ID.
Examples
var fixes = findFixesByID("POGIC");
foreach(var fix; fixes){
print(fix.id, " - lat: ", fix.lat, " | lon: ", fix.lon); # prints information about POGIC
}
var fix = findFixesByID("ZUNAP");
fix = fix[0];
var (course, dist) = courseAndDistance(fix);
print("Turn to heading ", math.round(course), ". You have ", sprintf("%.2f", dist), " nm to go to reach ", fixes[0].id);
findNavaidByFrequencyMHz([pos, ]freq[, type]);
Returns a navaid
ghost object for a navaid matching a given frequency. If there is more than one navaid with that frequency, the nearest station is returned.
- pos
- Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object
- Two numbers separated by a comma, as if the function is taking three arguments. Example:
findNavaidByFrequencyMHz(lat, lon, freq, type);
.
- An
- freq
- Frequency, in megahertz, of the navaid to search for.
- type
- This will narrow the search to navaids of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 127).
Example
var navaid = findNavaidByFrequencyMHz(109.55);
print("ID: ", navaid.id); # prints info about the navaid
print("Name: ", navaid.name);
print("Latitude: ", navaid.lat);
print("Longitude: ", navaid.lon);
print("Elevation (AMSL): ", navaid.elevation, " m");
print("Type: ", navaid.type);
print("Frequency: ", sprintf("%.3f", navaid.frequency / 100), " Mhz");
print("Range: ", navaid.range_nm, " nm");
if(navaid.course) print("Course: ", navaid.course);
findNavaidsByFrequencyMHz([pos, ]freq[, type]);
Returns a vector conatining navaid
ghost objects for navaids that match a given frequency, sorted from nearest to furthest.
- pos
- Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object
- Two numbers separated by a comma, as if the function is taking three arguments. Example:
findNavaidsByFrequencyMHz(lat, lon, freq, type);
.
- An
- freq
- Frequency, in megahertz, of the navaid to search for.
- type
- This will narrow the search to navaids of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 127).
Example
var navaids = findNavaidsByFrequencyMHz(109.55);
foreach(var navaid; navaids){
print("--");
print("ID: ", navaid.id); # prints info about the navaid
print("Name: ", navaid.name);
print("Latitude: ", navaid.lat);
print("Longitude: ", navaid.lon);
print("Elevation (AMSL): ", navaid.elevation, " m");
print("Type: ", navaid.type);
print("Frequency: ", sprintf("%.3f", navaid.frequency / 100), " Mhz");
print("Range: ", navaid.range_nm, " nm");
if(navaid.course) print("Course: ", navaid.course);
print("--");
}
findNavaidsByID([pos, ]id[, type]);
Returns a vector containing navaid
ghost objects matching a given ID, sorted by range from a certain position.
- pos
- Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object
- Two numbers separated by a comma, as if the function is taking three arguments. Example:
findNavaidsByID(lat, lon, id, type);
.
- An
- id
- Full or partial ID of the fix to search for.
- Note Inputting a partial ID does not work correctly (see here). It is best to just input a full ID.
- type
- This will narrow the search to navaids of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 127).
Example
var navaid = findNavaidsByID("MXW");
navaid = navaid[0];
print("ID: ", navaid.id); # prints info about 'MXW' (a VOR station)
print("Name: ", navaid.name);
print("Latitude: ", navaid.lat);
print("Longitude: ", navaid.lon);
print("Elevation (AMSL): ", navaid.elevation, " m");
print("Type: ", navaid.type);
print("Frequency: ", sprintf("%.3f", navaid.frequency / 1000), " Mhz");
print("Range: ", navaid.range_nm, " nm");
findNavaidsWithinRange([pos, ]range[, type]);
Returns a vector of navaid
ghost objects which are within a given range of a given position (by default the aircraft's current position). The results are sorted from closest to furthest.
- pos
- Optional position to search around. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost type - A hash with lat and lon members
- A geo.Coord object
- Two numbers separated by a comma, as if the function is taking three arguments. Example:
findNavaidsWithinRange(lat, lon, range, type);
.
- An
- range
- Mandatory number giving the range in nautical miles within which to search for navaids.
- type
- This will narrow the search to navaids of a certain type. Defaults to "all." For the full list of accepted type arguments, see flightgear/src/Navaids/positioned.cxx (line 127).
Examples
Searches for navaids within 10 nm of KSFO.
var pos = airportinfo("KSFO");
var navs = findNavaidsWithinRange(pos, 10);
foreach(var nav; navs){
print(nav.name, " (ID: ", nav.id, ")");
}
Searches for navaids within 10 nm of your current position.
var navs = findNavaidsWithinRange(10);
foreach(var nav; navs){
print(nav.name, " (ID: ", nav.id, ")");
}
finddata()
finddata(path);
Takes a relative path and tries to return an absolute one. It works by appending the relative path to some paths and testing to see if they exist. As of FlightGear v3.7, these paths are the TerraSync directory (tested first) and $FG_ROOT.
- path
- A relative path as a string.
Examples
var path = finddata("Aircraft/Generic");
print(path); # prints the absolute path to $FG_ROOT/Aircraft/Generic
var path = finddata("Airports");
print(path); # prints the absolute path to <TerraSync dir>/Airports
var path = finddata("preferences.xml");
print(path); # prints the absolute path to $FG_ROOT/preferences.xml
flightplan()
flightplan([path]);
Returns a flight plan object, either one for the current flight plan, or one loaded from a given path.
- path
- Optional path to flight plan XML file.
Examples
Gets the active flight plan and gets the ID of the current waypoint. Note that this example requires a flight plan to be set in the Route Manager first.
var fp = flightplan();
print(fp.getWP(fp.current).id);
Creates a new flight plan from an XML file and prints the IDs of the waypoints. Note that this example requires a flight plan to have been created and saved as $FG_HOME/fp-demo.xml.
var path = getprop('/sim/fg-home') ~ '/fp-demo.xml';
var fp = flightplan(path);
for(var i = 0; i < fp.getPlanSize(); i += 1){
print(fp.getWP(i).id);
}
geodinfo()
geodinfo(lat, lon[, max_alt]);
Returns a vector containing two entries or nil
if no information could be obtained because the terrain tile wasn't loaded. The first entry in the vector is the elevation (in meters) for the given point, and the second is a hash with information about the assigned material (as defined in $FG_ROOT/Materials), or nil
if there was no material information available (for example, because there is an untextured building at that location). The structure of the hash is as follows (see also $FG_ROOT/Docs/README.materials):
- light_coverage: The coverage of a single point of light in m2.
- bumpiness: Normalized bumpiness factor for the material.
- load_resistance: The amount of pressure in N/m2 the material can withstand without deformation.
- solid: 1 (true) or false (0) depending on whether the material is solid or not.
- names: Vector of scenery types (usually generated by TerraGear) that will use this material.
- friction_factor: Normalized friction factor of the material.
- rolling_friction: The rolling friction coefficient of the material.
Note that this function is a very CPU-intensive operation, particularly in FlightGear v2.4 and earlier. It is advised to use this function as little as possible.
- lat
- Latitude, inputted as a number.
- lon
- Longitude, inputted as a number.
- max_alt
- The altitude, in metres, from which the function will begin searching for the height of the terrain. Defaults to 10,000 metres. If the terrain is higher than this argument specifies,
nil
will be returned.
Examples
Dumps information about ground underneath the aircraft.
var pos = geo.aircraft_position();
var info = geodinfo(pos.lat(), pos.lon());
debug.dump(info);
Prints whether the ground underneath the aircraft is solid or is water.
var pos = geo.aircraft_position();
var info = geodinfo(pos.lat(), pos.lon());
if (info != nil and info[1] != nil) {
print("The ground underneath the aircraft is ", info[1].solid == 1 ? "solid." : "water.");
}
geodtocart()
geodtocart(lat, lon, alt);
Converts geodetic coordinates (latitude, longitude, and altitude) to Earth-centered, Earth-fixed coordinates (x, y and z). A vector is returned containing x, y, and z in metres. The equatorial radius of earth used is that defined by the WGS 84 (6,378,137 metres). All argument are mandatory.
- lat
- Latitude, in degrees.
- lon
- Longitude, in degrees.
- alt
- Altitude, in metres.
Example
var (x, y, z) = geodtocart(0, 0, 0); # point is the intersection of the prime meridian and equator.
print("x: ", x); # prints "x: 6378137"
print("y: ", y); # prints "y: 0"
print("z: ", z); # prints "y: 0"
get_cart_ground_intersection()
Introduced in 2017.2.1, see Terrain Detection.
getprop()
getprop(path[, path[, ...]]);
Returns the value of a node in the Property Tree or nil
if the node does not exist or the value is not a number (NaN).
- path
- There needs to be at least one argument, but there is no limit to the maximum amount of arguments that can be given. The arguments will be concatenated together to form a property tree path. The arguments must be strings, but in FlightGear v3.2 onwards, there is also support (added by FlightGear commit 34ed79) for numeric arguments as indices. See example 2 below.
Examples
print("You have FlightGear v", getprop("/sim/version/flightgear")); # prints FlightGear version
Note that the example below will only work in FlightGear 3.2 and above.
for(var i = 0; i < 8; i += 1){
print("View #", i + 1, " is named ", getprop("/sim/view", i, "name"));
}
Same as above, but is supported by all versions of FlightGear.
for(var i = 0; i < 8; i += 1){
print("View #", i + 1, " is named ", getprop("/sim/view[" ~ i ~ "]/name"));
}
See also
Note If you have to read/write the same property multiple times (e.g. in an update loop), it is more efficient to use a node object:
To get a Node rather than its value, use |
greatCircleMove()
greatCircleMove([pos, ]course, dist);
Calculates a new set of geodetic coordinates using inputs of course and distance, either from the aircraft's current position (by default) or from another set of coordinates. Returns a hash containing two members, lat and lon (latitude and longitude respectively).
- pos
- Optional position to calculate from. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost object. - A hash with lat and lon members
- A
geo.Coord
object - A lat/lon pair, that is, a pair of numbers (latitude followed by longitude) separated by a comma:
greatCircleMove(lat,lon, ...)
.
- An
- course
- Course to new set of coordinates, in degrees (in the range 0–360).
- dist
- Distance in nautical miles to the new set of coordinates.
Examples
var pos = greatCircleMove(0,0, 0, 1);
debug.dump(pos); # print hash with coordinates
var fix = findFixesByID("POGIC");
fix = fix[0];
var pos = greatCircleMove(fix, 45, 10);
debug.dump(pos); # print hash with coordinates
interpolate()
- _interpolate()
interpolate(prop, value1, time1[, value2, time2[, ...]]);
Linearly interpolates a node in the property tree to a given value in a specified time. The value/time pairs will be run one after the other in the order that they are passed to the function. Note that the interpolation will continue even when the simulation is paused.
- prop
- String or
props.Node
object that indicates a node in the property tree to be used. - valuen
- Target value to change the property to in the set amount of time. This should be a number.
- timen
- Time in seconds, that will be taken for the interpolation.
Examples
Paste the code below into the Nasal Console and execute. Then, open the Property Browser and look for the property. Finally, run the code again, and watch the value of the property change.
setprop("/test", 0); # (re-)set property
interpolate("/test",
50, 5, # interpolate to 50 in 5 seconds
10, 2, # interpolate to 10 in 2 seconds
0, 5); # interpolate to 0 in 5 seconds
# Apply the left brake at 20% per second
var prop = "controls/gear/brake-left";
var dist = 1 - getprop(prop);
if (dist == 1) {
interpolate(prop, 1, dist / 0.2);
}
isa()
isa(object, class);
Checks if an object is an instance of, or inherits from, a second object (or class), returning 1 (true) if it is and 0 (false) if otherwise.
- object
- Object to check.
- class
- Class/object to check that object inherits from or is an instance of.
Examples
var coord = geo.Coord.new();
if(isa(coord, geo.Coord)){
print("Variable 'coord' is an instance of class 'geo.Coord'"); # this one will be printed
} else {
print("Variable 'coord' is not an instance of class 'geo.Coord'");
}
var coord = geo.Coord.new();
if(isa(coord, props.Node)){
print("Variable 'coord' is an instance of class 'props.Node'");
} else {
print("Variable 'coord' is not an instance of class 'props.Node'"); # this one will be printed
}
The example below demonstrates checking of inheritance.
var Const = {
constant: 2,
getConst: func {
return me.constant;
}
};
var Add = {
new: func {
return { parents: [Add, Const] };
},
addToConst: func(a){
return a * me.getConst();
}
};
var m = Add.new();
print(m.addToConst(4));
if(isa(m, Add)) print("Variable 'm' is an instance of class 'Add'"); # will be printed
if(isa(m, Const)) print("Variable 'm' is an instance of class 'Const'"); # will also be printed
logprint()
logprint(priority[, msg[, msg[, ...]]]);
Concatenates a message and logs it with a given priority level. Unlike print()
and printlog()
, message outputted by this function will be logged in your fgfs.log
file as coming from the Nasal file itself rather than from flightgear/src/Scripting/NasalSys.cxx.
- priority
- Number specifying the priority level of the outputted message:
Number Debug type 1 Bulk 2 Debug 3 Info 4 Warn 5 Alert
- msg
- The message. There is no limit to the arguments you give give. They will be concatenated together before logging.
Examples
# logs the value of pi to three decimal places with log level 3
logprint(3, "pi = ", sprintf("%.3f", math.pi));
logprint(5, "Alert! This is an important message!");
Note
The following constants have been added to the development branch of FlightGear ("next") and will be releases with FG 2020.1 so you won't have to remember the numbers anymore: LOG_BULK, LOG_WARN, LOG_DEBUG, LOG_INFO, LOG_ALERT, DEV_WARN, DEV_ALERT |
magvar()
magvar([pos]);
Returns the magnetic variation at a given set of coordinates. The table below gives the magnetic model used depending on the version of FlightGear.
FlightGear versions | Model | Reference date |
---|---|---|
3.6 and above | World Magnetic Model (WMM) 2015 | 1 January 2015 |
0.9.11-pre1 to 3.4 | WMM 2005 | 1 January 2005 |
0.7.3 to 0.9.10 | WMM 2000 | 1 January 2000 |
- pos
- Optional position to calculate from. If not given, the aircraft's current position will be used. Can be one of:
- An
airport
,navaid
,runway
,taxiway
,fix
, orwaypoint
ghost object. - A hash with lat and lon members
- A
geo.Coord
object - A lat/lon pair, that is, a pair of numbers (latitude followed by longitude) separated by a comma:
magvar(lat,lon)
.
- An
Example
print(magvar(0, 0)); # prints the magnetic variation at 0, 0
maketimer()
maketimer(interval[, self], function);
Implemented using the TimerObj
(doxygen) class.
Part 1 | Part 2 — Version added: FG 2.12 (commit)
Returns a timer object containing the following methods and members:
- start(): Starts the timer.
- stop(): Stops the timer.
- restart(interval): Restarts the timer with the given interval.
- singleShot: Bool showing whether the timer is only to be run once, or continuously until told to stop. Can be both set and read from (see examples).
- isRunning: Read-only bool telling whether the timer is currently running.
- simulatedTime: (FG 2017.1+; commit) Bool telling whether the timer is using simulated time (which accounts for pause, etc.). Defaults to false (use real time). Can be both read and set. This cannot be changed while the timer is running.
Unlike settimer()
, which it replaces, maketimer()
provides more control over the timer. In addition, it can help reduce memory usage.
- interval
- Interval in seconds for the timer.
- self
- Optional parameter specifying what any
me
references in the function being called will refer to. - function
- Function to be called at the given interval.
Examples
var timer = maketimer(1, func(){
print("Hello, World!"); # print "Hello, World!" once every second (call timer.stop() to stop it)
});
timer.start();
var timer = maketimer(1, math, func(){
print(me.math); # 'me' reference is the 'math' namespace
});
timer.singleShot = 1; # timer will only be run once
timer.start();
var timer = maketimer(1, func(){
print("Hello, World!"); # print "Hello, World!" once every second (call timer.stop() to stop it)
});
timer.start();
print(timer.isRunning); # prints 1
In the example below, "Hello, World!" will be printed after one second the first time, and after two seconds thereafter.
var update = func(){
print("Hello, World!");
timer.restart(2); # restarts the timer with a two second interval
}
var timer = maketimer(1, update);
timer.singleShot = 1;
timer.start();
maketimestamp()
maketimestamp()
Implemented using the TimeStampObj
(doxygen) class.
Part 1 | Part 2 — Version added: FG 2019.2 (commit)
Returns a time stamp object to allow high resolution timing of Nasal operations. When created the timer will automatically be stamped. The object has the following methods:
- stamp(): Resets the timing operation. Call this first.
- elapsedMSec(): returns number of milliseconds elapsed since stamp() called. Resolution may vary depending on platform but is usually at least millisecond accuracy.
- elapsedUSec(): returns number of microseconds elapsed since stamp() called. Resolution may vary depending on platform but is usually at least millisecond accuracy.
Example
In the example below the number of milliseconds elapsed will be printed.
var timestamp = maketimestamp();
timestamp.stamp();
print(timestamp.elapsedMSec(), "ms elapsed");
print(timestamp.elapsedMSec(), "ms elapsed");
md5()
md5(string);
Source — Version added: FG 3.2 (commit)
Returns a the MD5 hash (as a string) of the inputted string.
- string
- String the generate the hash of. Mandatory.
Example
The below code should output 65a8e27d8879283831b664bd8b7f0ad4
.
print(md5("Hello, World!"));
navinfo(lat, lon, type, id);
Returns vector navaid
ghost objects matching the given type and id or nil
on error.
- lat and lon
- If given, the returned navaids will be put into order of ascending distance from the location.
- type
- Narrows the search to the given type. Must be one of "any," "fix," "vor," "ndb," "ils," "dme," or "tacan." Defaults to the equivalent of "any."
- id
- ID to search for. Note that, although all the parameters are technically optional, this parameter must be given, otherwise an empty vector will be returned.
Examples
navinfo("vor"); # returns all VORs
navinfo("HAM"); # return all navaids whose names start with "HAM"
navinfo("vor", "HAM"); # return all VORs whose names start with "HAM"
navinfo(34,48,"vor","HAM"); # return all VORs whose names start with "HAM" and sorted by distance relative to 34°, 48°
parse_markdown()
parse_markdown(markdown);
Part 1 | Part 2 — Version added: FG 3.2
Parses a string containing Markdown and returns the result as a string. As of FlightGear 2016.1, it is just a simple parser, and does the following:
- It strips whitespace from the beginning of the string.
- It supports paragraphs and line breaks.
- It collapses whitespace.
- It converts unordered lists to use a bullet character (•). Note that the bullet character is implemented in hexadecimal UTF-8 character bytes (
E2 80 A2
), as so may not work properly when the being displayed in an encoding other than UTF-8.
- markdown
- String containing Markdown to be parsed.
Examples
Save the below code as $FG_ROOT/gui/dialogs/test.xml, then run the Nasal code below it to open the dialog. To change the markdown to be parsed, simply change the code in the highlighted section, save it, and reload the GUI (Debug > Reload GUI).
<?xml version="1.0" encoding="UTF-8"?>
<PropertyList>
<name>test</name>
<layout>vbox</layout>
<group>
<layout>hbox</layout>
<empty>
<stretch>true</stretch>
</empty>
<text>
<label>parse_markdown() test dialog</label>
</text>
<empty>
<stretch>true</stretch>
</empty>
<button>
<legend></legend>
<pref-width>16</pref-width>
<pref-height>16</pref-height>
<binding>
<command>dialog-close</command>
</binding>
</button>
</group>
<canvas>
<name>Canvas plot</name>
<stretch>true</stretch>
<pref-width>400</pref-width>
<pref-height>300</pref-height>
<nasal>
<load><![CDATA[
var text = 'Items:
* apples
* oranges
* pears
Some text.
Some more items:
* apples
* oranges
* pears';
var parsed = parse_markdown(text);
var root_canvas = canvas.get(cmdarg());
root_canvas.setColorBackground(255, 255, 255);
var root = root_canvas.createGroup();
var text_dis = root.createChild("text")
.setText(parsed)
.setTranslation(5, 5)
.setFont("LiberationFonts\LiberationSans-Regular.ttf")
.setFontSize(15)
.setColor(0, 0, 0)
.setDrawMode(canvas.Text.TEXT)
.setAlignment("left-top");
]]></load>
</nasal>
</canvas>
</PropertyList>
fgcommand("dialog-show", {"dialog-name": "test"});
The example below parses Markdown and outputs it in a HTML document. The parsed text is placed in <pre></pre>
tags. To change the Markdown to be parsed, simply edit the variable markdown at the top of the code.
var markdown = 'Items:
* apples
* oranges
* pears
Some text.
Some more items:
* apples
* oranges
* pears';
var parsed = parse_markdown(markdown);
debug.dump(parsed);
var path = string.normpath(getprop("/sim/fg-home") ~ '/Export/parse_markdown()-test.html');
var file = io.open(path, "w");
var html = "<!DOCTYPE html>\n\n<html>\n\n<head>\n\t<meta charset=\"UTF-8\">\n\t<title>parse_markdown() test generated by Nasal</title>\n</head>\n\n<body>\n\t<pre>" ~ parsed ~ "</pre>\n</body>\n\n</html>";
io.write(file, html);
io.close(file);
print("Done, file ready for viewing (" ~ path ~ ")");
parsexml()
parsexml(path[, start[, end[, data[, pro_ins]]]]);
This function is an interface into the built-in Expat XML parser. The absolute path to the file is returned as string, or nil
is returned on error.
- path
- Mandatory absolute path to the XML file to be parsed.
- start
- Optional callback function that will be called for every starting tag. The function should take two argument: the tag name and a hash containing attributes.
- end
- Optional callback function that will be called for every ending tag. The function should take one argument: the tag name.
- data
- Optional callback function that will be called for every piece of data within a set of tags. The function should take one argument: the data as a string.
- pro_ins
- Optional callback function that will be called for every processing instruction . The function should take two argument: the target and the data string.
Example
Save the below XML code in $FG_HOME/Export/demo.xml. Then, execute the Nasal code below in the Nasal Console. The XML will be parsed and each bit of the code will be printed.
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<foo>
<blah type="string"><![CDATA[ <sender>John Smith</sender> ]]></blah>
<blah2 type="string">Orange & lemons</blah2>
</foo>
var start = func(name, attr){
print("Starting tag: '", name, "'");
foreach(var a; keys(attr)){
print("\twith attribute ", a, '="', attr[a], '"');
}
}
var end = func(name){
print("Ending tag: '", name, "'");
}
var data = func(data){
print("Data = '", data, "'");
}
var pro_instr = func(target, data){
print("Processing instruction: target = '", target, "', data = '", data, "'");
}
parsexml(getprop("/sim/fg-home") ~ '/Export/demo.xml', start, end, data, pro_instr);
print()
Note As of 07/2020, we are in the process of slowly deprecating and removing Nasal print() (in fgdata) where possible in favor of log #logprint() which takes a priority level.
This is part of the goal that we achieve zero output at log-level at alert, and everything shown at ‘warn; is really a warning, not just information.[4] |
print(data[, data[, ...]]);
Concatenates its arguments and then prints it to the terminal and the log. Note that a newline is automatically added.
- data
- Data to print. Only strings and numbers can be printed; other data types will not be. There many be any number of arguments; they will just be concatenated together.
Examples
print("Just", " a ", "test"); # prints "Just a test"
print("pi = ", math.pi); # prints "pi = 3.141592..."
printf()
printf(format[, arg[, arg, [...]]]);
Creates and prints a formatted string. For a description of its arguments, see sprintf()
(it is, in fact, implemented using sprintf()
).
Example
printf("In hexadecimal, 100000 = %X", 186A0); # prints "In hexadecimal, 100000 = 186A0"
printlog()
printlog(level, data[, data[, ...]]);
Prints the given message with the given log level. If the log level is higher or equal to /sim/logging/priority
, it is printed.
- level
- Mandatory log level as a string. Must be one of "none," "bulk," "debug," "info," "warn," or "alert." Note that "none" will mean that the message will never be printed.
- data
- Data to be printed. Only strings and numbers will be printed; others will not be. There may be any number of arguments; they will just be concatenated together.
Examples
printlog("alert", "This is an alert"); # message will be printed
printlog("info", "Just informing you about something"); # message will be printed only if log level is set to "info" or less
rand()
rand();
Returns a random floating point number between 0 (inclusive) and 1 (exclusive). It takes no arguments.
Example
print(rand()); # prints random number
registerFlightPlanDelegate()
registerFlightPlanDelegate(init_func);
Registers a flight plan delegate. See $FG_ROOT/Nasal/route_manager.nas for examples.
- init_func
- Initialization function which will be called during FlightGear's startup.
removecommand()
removecommand(cmd);
Removes the given fgcommand. Returns nil
.
Caution This will remove any fgcommand, even those implemented in C++, so use with caution! |
- cmd
- String specifying the name of the command to remove.
Example
addcommand("hello", func(){
print("Hello");
});
fgcommand("hello"); # "Hello" will be printed
removecommand("hello"); # removes it
removelistener()
removelistener(id);
Removes and deactivates the given listener and returns the number of listeners left or nil
on error.
Note It is good practice to remove listeners when they are not required anymore. This prevents the listeners reducing FlightGear's run performance. |
- id
- ID of listener as returned by
setlistener()
.
Example
var ls = setlistener("/sim/test", func(){
print("Property '/sim/test' has been changed");
});
setprop("/sim/test", "blah"); # trigger listener
var rem = removelistener(ls); # remove listener
print("There are ", rem, " listeners remaining");
resolvepath()
resolvepath(path);
Takes a relative path as a string and uses SimGear's path-resolving framework to return an absolute path as a string. If the path could not be resolved, an empty string is returned. See Resolving Paths for a detailed description of the algorithm. This function can also be used to check if a file exists.
- path
- Relative path to be completed.
Examples
print(resolvepath("Nasal/globals.nas")); # prints the equivalent of $FG_ROOT/Nasal/globals.nas
print(resolvepath("blah")); # prints nothing; could not be resolved
var file_path = resolvepath("Aircraft/SenecaII/some-file");
if (file_path != ""){
gui.popupTip("some-file found", 2);
} else {
gui.popupTip("some-file not found", 2);
}
setlistener()
- _setlistener()
setlistener(node, code[, init[, type]]);
Part 1 | Part 2
Listener implemented using the FGNasalListener
(doxygen) class.
Creates a listener which will be triggered when the given property is changed (depending on the type). A unique integer ID is returned; this can later be used as the argument to removelistener()
.
Note Listeners are known to be a source of resource leaks. To avoid this, please take measures such as:
|
- node
- Mandatory string or
props.Node
object pointing to a property in the Property Tree. - code
- Mandatory callback function to execute when the listener is triggered. The function can take up to four arguments in the following order:
- changed: a
props.Node
object pointing to the changed node. - listen: a
props.Node
object pointing to the listened-to node. Note that this argument maybe different depending on the type. - mode: an integer telling how the listener was triggered. 0 means that the value was changed. 1 means that a child property was added. -1 means that a child property was removed.
- is_child: boolean telling whether changed is a child property of the listened-to node or not. 1 (true) if it is, 0 (false) otherwise.
- init
- If set to 1 (true), the listener will additionally be triggered when it is created. This argument is optional and defaults to 0 (false).
- type
- Integer specifying the listener's behavior. 0 means that the listener will only trigger when the property is changed. 1 means that the trigger will always be triggered when the property is written to. 2 will mean that the listener will be triggered even if child properties are modified. This argument is optional and defaults to 1.
Example
var prop = props.globals.initNode("/sim/test", "", "STRING"); # create property
var id = setlistener("/sim/test", func(n){ # create listener
print("Value: ", n.getValue());
});
setprop("/sim/test", "blah"); # trigger listener
removelistener(id); # remove listener
prop.remove(); # remove property
setprop()
setprop(path[, path[, ...]], value);
Sets the value of a property in the Property Tree. If the property does not exist, it will be created. Returns 1 (true) on success or 0 (false) if there was an error.
Note If you want to remove a property, you will have to use one of the props helpers:
props.globals.getNode("foo/bar").remove(); # take out the complete node
props.globals.getNode("foo").removeChild("bar"); # take out a certain child node |
- path
- There needs to be at least one path argument, but there is no limit to the maximum amount that can be given. They will be concatenated together to form a property tree path. The arguments must be strings, but in FlightGear v3.2 onwards, there also is support (added by FlightGear commit 34ed79) for numeric arguments as indices. See example 2 below.
- value
- Value to write to the given property. Must be either a string or a number.
Examples
setprop("/sim/demo", "This is a demo");
Note that the example below will only work in FlightGear 3.2 and above.
for(var i = 0; i < 3; i += 1){
setprop("/sim/demo", i, "Demo #" ~ i));
}
Same as above, but is supported by all versions of FlightGear.
for(var i = 0; i < 3; i += 1){
setprop("/sim/demo[" ~ i ~ "]", "Demo #" ~ i));
}
See also
Note If you have to read/write the same property multiple times (e.g. in an update loop), it is more efficient to use a node object:
To get a Node rather than its value, use |
settimer()
settimer(function, delta[, realtime]);
Runs the given function a specified amount of seconds after the current time. Returns nil
.
Note Improper use of settimer() may cause resource leaks. It is also highly recommended that the newer maketimer() should be used instead of this function.
|
- function
- Mandatory function that will be called. It may be necessary to enclose code in an anonymous function (see example).
- delta
- Mandatory amount of time in seconds after which the function will be called.
- realtime
- If 1 (true), "real time" will be used instead of "simulation time." Defaults to 0 (false). Note that if "simulation time" is used, the timer will not run while FlightGear is paused.
Examples
var myFunc = func(){
print("Hello");
}
settimer(myFunc, 2); # runs myFunc after 2 seconds
var sqr = func(a){
return a * a;
}
settimer(func(){
print(sqr(2)); # will print 4 after 2 seconds
}, 2);
srand()
srand();
Makes the pseudorandom number generator (see rand()
) generate a new random seed based on time. Returns 0.
systime()
systime();
Returns the Unix time (seconds since since 00:00:00 UTC, 1/1/1970) as a floating point number with high resolution. This function is useful for benchmarking purposes (see example 2).
Note High resolution timers under Windows can produce inaccurate or fixed sub-millisecond results.[5] This is due to the underlying GetSystemTimeAsFileTime() API call, which depends on hardware availability of suitable high resolution timers. See also Acquiring high-resolution time stamps
|
Examples
print("Unix time: ", systime()); # prints Unix time
var myFunc = func(){
for(var i = 0; i <= 10; i += 1){
print("Interation #", i);
}
}
var t = systime(); # record time
myFunc(); # run function
var t2 = systime(); # record new time
print("myFunc() took ", t2 - t, " seconds"); # print result
thisfunc()
thisfunc();
Returns the function from which this function is called. This allows a function to reliably and safely call itself from within a closure.
Example
var stringify_vec = func(input){
if (typeof(input) == "scalar"){
return sprintf("%s", input);
} elsif (typeof(input) == "vector") {
if (size(input) == 0) return "[]";
var this = thisfunc();
var buffer = "[";
for(var i = 0; i < size(input); i += 1){
buffer ~= this(input[i]);
if (i == size(input) - 1) {
buffer ~= "]";
} else {
buffer ~= ", ";
}
}
return buffer;
} else {
die("stringify_vec(): Error! Invalid input. Must be a vector or scalar");
}
}
var test_vec = ["a", "b", "c", 1, 2, 3];
debug.dump(stringify_vec(test_vec)); # prints "[a, b, c, 1, 2, 3]"
test_vec = [];
debug.dump(stringify_vec(test_vec)); # prints "[]"
test_vec = {};
debug.dump(stringify_vec(test_vec)); # will throw an error
tileIndex()
tileIndex();
Returns the index of the tile at the aircraft's current position as a string. This corresponds to the name of the STG file of the tile. For example, at KSFO, this would be 942050
, corresponding to $FG_SCENERY/Terrain/w130n30/w123n3/942050.stg.
Example
print(tileIndex()); # print index
tilePath()
tilePath();
Returns the base path of the tile at the aircraft's current position as a string. For example, at KSFO, this would be w130n30/w123n3
, corresponding to $FG_SCENERY/Terrain/w130n30/w123n3.
Example
print(tilePath()); # print path
values()
values(hash);
Returns a vector containing the values of the given hash.
- hash
- Mandatory hash to get the values of.
Examples
var hash = {
"a": 1,
"b": 2,
"c": 3
};
foreach(var val; values(hash)){
print(val);
}
The below example does exactly the same thing as the above example, but does not use values()
:
var hash = {
"a": 1,
"b": 2,
"c": 3
};
foreach(var key; keys(hash)){
print(hash[key]);
}
Extension functions new in FG 2020.1
The following functions have been added to the nasal core library and will be released with FlightGear version 2020.1. Before the release they are available in the development branch "next".
isfunc()
Returns 1 if type or argument is a function, otherwise 0.
isghost()
Returns 1 if type or argument is a ghost, otherwise 0.
ishash()
Returns 1 if type or argument is a hash, otherwise 0.
isint()
isint(x);
Returns 1 if argument has a numeric value and x == floor(x), e.g. integer.
isnum()
isnum(x);
Returns 1 if typeof(x) is "scalar" and x has a numeric value otherwise 0.
isscalar()
isscalar(x);
Returns 1 if type or argument is a scalar (string or numeric), otherwise (vector, hash, func, ...) it returns 0. This is useful to check if a variable can be converted to string e.g. when useing the string concat operator "~".
Example
var a = "foo";
var b=42;
if (isscalar(a) and isscalar(b)) print(a~b);
if (isstr(a)) print("a is a string");
if (isint(b)) print("b is an integer");
# if (isscalar(a))... is equivalent to if (typeof(a) == "scalar")...
isstr()
Returns 1 if type or argument is a string, otherwise 0.
isvec()
Returns 1 if type or argument is a vector, otherwise 0.
vecindex()
vecindex(vector, value);
Returns the index of value or nil, if value is not found in vector.
Example
var myvector = ["apple", "bananna", "coconut"];
# to check if a vector contains a certain value compare vecindex to nil
if (vecindex(myvector, "apple") != nil) {
print("found apple");
}
# WARNING: this will not work as desired because index is 0
if (vecindex(myvector, "apple")) {
print("found apple");
}
Variables
Various global constants (technically variables) are provided for use in converting between different units. They are all found in fgdata/Nasal/globals.nas.
D2R
var radians = degrees * D2R;
Converts an angle from degrees to radians when multiplied by the angle in degrees. Equal to π / 180
.
FPS2KT
var knots = feet_per_second * FPS2KT;
Converts a velocity from feet per second to knots when multiplied by the velocity in feet per second. Approximately equal to 0.5925.
FT2M
var metres = feet * FT2M;
Converts a length from feet to metres when multiplied by the length in feet. Equal to 0.3048.
GAL2L
var litres = gallons * GAL2L;
Converts a volume from US liquid gallons to litres when multiplied by the volume in gallons. Approximately equal to 3.7854.
IN2M
var metres = inches * IN2M;
Converts a length from inches to metres when multiplied by the length in inches. Equal to 0.0254.
KG2LB
var pounds = kilograms * KG2LB;
Converts a mass from kilograms to pounds when multiplied by the mass in kilograms. Approximately equal to 2.2046.
KT2FPS
var feet_per_second = knots * KT2FPS;
Converts a velocity from knots to feet per second when multiplied by the velocity in knots. Approximately equal to 1.6878.
KT2MPS
var metres_per_second = knots * KT2MPS;
Converts a velocity from knots to metres per second when multiplied by the velocity in knots. Approximately equal to 0.5144.
L2GAL
var gallons = litres * L2GAL;
Converts a volume from litres to US liquid gallons when multiplied by the volume in litres. Approximately equal to 0.2642.
LB2KG
var kilograms = pounds * LB2KG;
Converts a mass from pounds to kilograms when multiplied by the mass in pounds. Approximately equal to 0.4536.
M2FT
var feet = metres * M2FT;
Converts a length from metres to feet when multiplied by the length in metres. Approximately equal to 3.2808.
M2IN
var inches = metres * M2IN;
Converts a length from metres to inches when multiplied by the length in metres. Approximately equal to 39.3701.
M2NM
var nautical_miles = metres * M2NM;
Converts a length from metres to nautical miles when multiplied by the length in metres. Approximately equal to 0.00054.
MPS2KT
var knots = metres_per_second * MPS2KT;
Converts a velocity from metres per second to knots when multiplied by the velocity in metres per second. Approximately equal to 1.9438.
NM2M
var metres = nautical_miles * NM2M;
Converts a length from nautical miles to metres when multiplied by the length in nautical miles. Equal to 1,852.
R2D
var degrees = radians * R2D;
Converts an angle from radians to degrees when multiplied by the angle in radians. Equal to 180 / π
.
References
|