Talk:Nasal scripting language

From FlightGear wiki
Jump to: navigation, search

Built-in functions

sort(vector, function)

Creates a new vector containing the elements in the input vector sorted in ascending order according to the rule given by function, which takes two arguments (elements of the input vector) and should return less than zero, zero, or greater than zero if the first argument is, respectively, less than, equal to, or greater than the second argument. Despite being implemented with ANSI C qsort(), the sort is stable; "equal" elements in the output vector will appear in the same relative order as they do in the input.

Because you can define the sort function, sort allows you to create a list of keys sorting a hash by any criterion--by key, value, or (if, for instance the hash values are hashes themselves) any subvalue.

vec = [100,24,45];
sortvec = sort (vec, func (a,b) cmp (a,b));
debug.dump (sortvec); #output is [24,45,100]

Here is an example of how to output the contents of a hash in sorted order. Note that the function does not actually sort the hash but returns a list of the hash keys in sorted order.

var airport = {
  "LOXZ": "Zeltweg",
  "LOWI": "Innsbruck",
  "LOXL": "Linz Hoersching",     # the last comma is optional
};

var sortedkeys= sort (keys(airport), func (a,b) cmp (airport[a], airport[b]));

foreach (var i; sortedkeys) 
 print (i, ": ", airport[i]);

The output is:

  LOWI: Innsbruck
  LOXL: Linz Hoersching
  LOXZ: Zeltweg  

If the hash values are themselves hashes, sorting by any of the subvalues is possible. For example:

var airport = {
   "LOXZ": {city: "Zeltweg", altitude_m: 1300 },
   "LOWI": {city: "Innsbruck", altitude_m: 2312 }, 
   "LOXL": {city: "Linz Hoersching", altitude_m: 1932 },
};
 
#return a list of the hash keys sorted by altitude_m
var sortedkeys= sort (keys(airport), func (a,b) airport[a].altitude_m - airport[b].altitude_m);
 
foreach (var i; sortedkeys) 
 print (i, ": ", airport[i].city, ", ", airport[i].altitude_m);

Note that sort will return errors, and in FG 2.4.0 may even stop working, if the sort function you provide returns errors. A common cause of this is if your sort vector contains both string and numeric values. The cmp function will return an error for numeric values, and arithmetic operations you may use to sort numeric values will return errors if performed on a string. The error in these cases is typically "function/method call on uncallable object".

Other useful built-in functions

Other basic built-in Nasal functions such as append, setsize, subvec, typeof, contains, delete, int, num, keys, pop, size, streq, cmp, substr, sprintf, find, split, rand, call, die, bind, math.sin, math.pi, math.exp, math.ln math.e, io.read, io.write, regex.exec, and others of that sort, are detailed in this external document.

Useful functions in the Nasal directory

Other functions are available in the Nasal files found in the Nasal directory of a FlightGear install. Simply open those Nasal files in text editor to see what is inside. Reference those functions by putting the filename in front of the function, method, variable, or object you wish to use. For instance, to use the method Coord.new() in the file geo.nas, you simply write:

geo.Coord.new()

Distance calculations

To calculate the distance between two points (in two different ways):

# mylat1, mylong1, mylat2, mylong2 are lat & long in degrees 
# myalt1 & myalt2 are altitude in meters

var GeoCoord1 = geo.Coord.new();
GeoCoord1.set_latlon(mylat1, mylong1,myalt1);

var GeoCoord2 = geo.Coord.new();
GeoCoord2.set_latlon(mylat2, mylong2, myalt2);

var directDistance = GeoCoord1.direct_distance_to(GeoCoord2);
var surfaceDistance = GeoCoord1.distance_to(GeoCoord2);

The results are distances in meters.

  • distance_to - returns distance in meters along Earth curvature, ignoring altitudes; useful for map distance
  • direct_distance_to - returns distance in meters direct; considers altitude, but cuts through Earth surface

Other useful geographical functions

Other useful geographical functions are found in geo.nas (in the $FG_ROOT/Nasal directory of a FlightGear installation). geo.nas also includes documentation/explanation of the functions available.

Related content

External links

Initializing data structures

There are some more possibilities to increase the density of your code, such as by removing redundant code or by generalizing and refactoring existing code so that it can be reused in different places (i.e. avoiding duplicate code):

For example see weather_tile_management.nas #1000 (create_neighbours function):

   1008 x = -40000.0; y = 40000.0;
   1009 setprop(lw~"tiles/tile[0]/latitude-deg",blat + get_lat(x,y,phi));
   1010 setprop(lw~"tiles/tile[0]/longitude-deg",blon + get_lon(x,y,phi));
   1011 setprop(lw~"tiles/tile[0]/generated-flag",0);
   1012 setprop(lw~"tiles/tile[0]/tile-index",-1);
   1013 setprop(lw~"tiles/tile[0]/code","");
   1014 setprop(lw~"tiles/tile[0]/timestamp-sec",weather_dynamics.time_lw);
   1015 setprop(lw~"tiles/tile[0]/orientation-deg",alpha);
   1016
   1017 x = 0.0; y = 40000.0;
   1018 setprop(lw~"tiles/tile[1]/latitude-deg",blat + get_lat(x,y,phi));
   1019 setprop(lw~"tiles/tile[1]/longitude-deg",blon + get_lon(x,y,phi));
   1020 setprop(lw~"tiles/tile[1]/generated-flag",0);
   1021 setprop(lw~"tiles/tile[1]/tile-index",-1);
   1022 setprop(lw~"tiles/tile[1]/code","");
   1023 setprop(lw~"tiles/tile[1]/timestamp-sec",weather_dynamics.time_lw);
   1024 setprop(lw~"tiles/tile[1]/orientation-deg",alpha);
   1025
   1026 x = 40000.0; y = 40000.0;
   1027 setprop(lw~"tiles/tile[2]/latitude-deg",blat + get_lat(x,y,phi));
   1028 setprop(lw~"tiles/tile[2]/longitude-deg",blon + get_lon(x,y,phi));
   1029 setprop(lw~"tiles/tile[2]/generated-flag",0);
   1030 setprop(lw~"tiles/tile[2]/tile-index",-1);
   1031 setprop(lw~"tiles/tile[2]/code","");
   1032 setprop(lw~"tiles/tile[2]/timestamp-sec",weather_dynamics.time_lw);
   1033 setprop(lw~"tiles/tile[2]/orientation-deg",alpha);
   1034
   1035 x = -40000.0; y = 0.0;
   1036 setprop(lw~"tiles/tile[3]/latitude-deg",blat + get_lat(x,y,phi));
   1037 setprop(lw~"tiles/tile[3]/longitude-deg",blon + get_lon(x,y,phi));
   1038 setprop(lw~"tiles/tile[3]/generated-flag",0);
   1039 setprop(lw~"tiles/tile[3]/tile-index",-1);
   1040 setprop(lw~"tiles/tile[3]/code","");
   1041 setprop(lw~"tiles/tile[3]/timestamp-sec",weather_dynamics.time_lw);
   1042 setprop(lw~"tiles/tile[3]/orientation-deg",alpha);
   1043
   1044 # this is the current tile
   1045 x = 0.0; y = 0.0;
   1046 setprop(lw~"tiles/tile[4]/latitude-deg",blat + get_lat(x,y,phi));
   1047 setprop(lw~"tiles/tile[4]/longitude-deg",blon + get_lon(x,y,phi));
   1048 setprop(lw~"tiles/tile[4]/generated-flag",1);
   1049 setprop(lw~"tiles/tile[4]/tile-index",1);
   1050 setprop(lw~"tiles/tile[4]/code","");
   1051 setprop(lw~"tiles/tile[4]/timestamp-sec",weather_dynamics.time_lw);
   1052 setprop(lw~"tiles/tile[4]/orientation-deg",getprop(lw~"tmp/tile-orientation-deg"));
   1053
   1054
   1055 x = 40000.0; y = 0.0;
   1056 setprop(lw~"tiles/tile[5]/latitude-deg",blat + get_lat(x,y,phi));
   1057 setprop(lw~"tiles/tile[5]/longitude-deg",blon + get_lon(x,y,phi));
   1058 setprop(lw~"tiles/tile[5]/generated-flag",0);
   1059 setprop(lw~"tiles/tile[5]/tile-index",-1);
   1060 setprop(lw~"tiles/tile[5]/code","");
   1061 setprop(lw~"tiles/tile[5]/timestamp-sec",weather_dynamics.time_lw);
   1062 setprop(lw~"tiles/tile[5]/orientation-deg",alpha);
   1063
   1064 x = -40000.0; y = -40000.0;
   1065 setprop(lw~"tiles/tile[6]/latitude-deg",blat + get_lat(x,y,phi));
   1066 setprop(lw~"tiles/tile[6]/longitude-deg",blon + get_lon(x,y,phi));
   1067 setprop(lw~"tiles/tile[6]/generated-flag",0);
   1068 setprop(lw~"tiles/tile[6]/tile-index",-1);
   1069 setprop(lw~"tiles/tile[6]/code","");
   1070 setprop(lw~"tiles/tile[6]/timestamp-sec",weather_dynamics.time_lw);
   1071 setprop(lw~"tiles/tile[6]/orientation-deg",alpha);
   1072
   1073 x = 0.0; y = -40000.0;
   1074 setprop(lw~"tiles/tile[7]/latitude-deg",blat + get_lat(x,y,phi));
   1075 setprop(lw~"tiles/tile[7]/longitude-deg",blon + get_lon(x,y,phi));
   1076 setprop(lw~"tiles/tile[7]/generated-flag",0);
   1077 setprop(lw~"tiles/tile[7]/tile-index",-1);
   1078 setprop(lw~"tiles/tile[7]/code","");
   1079 setprop(lw~"tiles/tile[7]/timestamp-sec",weather_dynamics.time_lw);
   1080 setprop(lw~"tiles/tile[7]/orientation-deg",alpha);
   1081
   1082 x = 40000.0; y = -40000.0;
   1083 setprop(lw~"tiles/tile[8]/latitude-deg",blat + get_lat(x,y,phi));
   1084 setprop(lw~"tiles/tile[8]/longitude-deg",blon + get_lon(x,y,phi));
   1085 setprop(lw~"tiles/tile[8]/generated-flag",0);
   1086 setprop(lw~"tiles/tile[8]/tile-index",-1);
   1087 setprop(lw~"tiles/tile[8]/code","");
   1088 setprop(lw~"tiles/tile[8]/timestamp-sec",weather_dynamics.time_lw);
   1089 setprop(lw~"tiles/tile[8]/orientation-deg",alpha);
   1090 }

At first glance, this seems like a fairly repetitive and redundant block of code, so it could probably be simplified easily:

   var create_neighbours = func (blat, blon, alpha)        {
   var phi = alpha * math.pi/180.0;
   calc_geo(blat);
   var index=0;
   var pos = [  [-40000.0,40000.0], [0.0, 40.000], [40000.0, 40000.0], [-40000, 0],  [0,0], [40000,0], [-40000,-40000], [0,-40000], [40000,-40000] ];
   foreach (var p;pos) {
   x=p[0]; y=p[1];
   setprop(lw~"tiles/tile["~index~"]/latitude-deg",blat + get_lat(x,y,phi));
   setprop(lw~"tiles/tile["~index~"]/longitude-deg",blon + get_lon(x,y,phi));
   setprop(lw~"tiles/tile["~index~"]/generated-flag",0);
   setprop(lw~"tiles/tile["~index~"]/tile-index",-1);
   setprop(lw~"tiles/tile["~index~"]/code","");
   setprop(lw~"tiles/tile["~index~"]/timestamp-sec",weather_dynamics.time_lw);
   setprop(lw~"tiles/tile["~index~"]/orientation-deg",alpha);
   index=index+1;
     }
   }


Contents that need to be incorporated

Todo

  • mention/explain nil
  • shorthand ops: += *= ~= /=
  • operator precedence, prioritizing expressions using parentheses
  • multi-assignments don't work as expected for functions with multiple return values

Mailing List Discussions

Usage

Features

Nasal Modules

Moving to Nasal Modules.