User talk:Awexome/WCA

From FlightGear wiki
Jump to navigation Jump to search

Named function arguments

#
## ##### BEGIN GPL LICENSE BLOCK #####
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# More topping for your chocolate, you ask? READ below!
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# General Public License for more details. <http://www.gnu.org/licenses/>
## ##### BEGIN GPL LICENSE BLOCK #####

# Useful References
# http://en.wikipedia.org/wiki/E6B
# http://en.wikipedia.org/wiki/Law_of_sines
# http://en.wikipedia.org/wiki/Inverse_trigonometric_functions
# Flightgear A380 project

#################################################
#    Trigonometric Constants and functions      #
#===============================================#

var acos = func(x) { 
  math.atan2(math.sqrt(1-x*x), x) 
}

var asin = func(x) {
 math.atan2(x,math.sqrt(math.pow(2,1-x)));
}

var degMin2rad = func(deg, min) {
  var d1 = deg+(min/60);
  return d1*(math.pi/180);
}

var nm2rad = func(d) {
 return d*math.pi / 
}

###############################################################################
# calculate WCA for course TCrs, speed of TAS, wind heading of wDir, and 
# related speed of WS; and the desired unit of output [nil,0-deg; 1-rad]
#=============================================================================#
var getWCA = func {
# arguments: TCrs, TAS, WDir, WS [, optional - DEG[0|nil] | RAD[1]]
# output: WCA - Wind Correction Angle

  var TCrs = arg[0] ? geo.normdeg(arg[0]) : getprop("/orientation/heading-deg");
  var TAS = arg[1] or getprop("/velocities/airspeed-kt");
  var WDir = arg[2] or geo.normdeg(getprop("/environment/wind-from-heading-deg") + 180);
  var WS = arg[3] or getprop("/environment/wind-speed-kt");

# WCA = asin(WS90 / TAS) : WS90 - wind speed (90deg component); TAS - True Air Speed
# WS90 = WS * sin(AC - Wind)[direction in degrees];
  var DEG2RAD = 0.01745329;
  var WTAngle = (TCrs - WDir);
  var WScoef = math.sin(WTAngle);
  var WS90 = WS * WScoef;
  var WCA = asin(WS90 / TAS);
  return WCA * (arg[4] ? DEG2RAD : 1);
  
# example use for heading correction for course newCrs
# var hdg = newCrs + getWCA(newCrs);
} # getWCA

###############################################################################
#  calculate distance between two GPS positions in degrees
#=============================================================================#
var calcGPSDistDeg = func (lat1, lon1, lat2, lon2) { 
# arguments 
 var DEG2RAD = 0.01745329;
 lat1 *= DEG2RAD;
 lon1 *= DEG2RAD;
 lat2 *= DEG2RAD;
 lon2 *= DEG2RAD;
 return me.calcGPSDist(lat1, lon1, lat2, lon2);
} # calcGPSDistDeg

###############################################################################
#  calculate distance between two GPS positions in radians, returns NM
#=============================================================================#
var calcGPSDist = func (lat1, lon1, lat2, lon2) {
 var d1 = math.sin((lat1-lat2)/2);
 var p1 = math.pow(2, d1);
 var dd2 = (math.sin((lon1-lon2)/2));
 var d2 = math.cos(lat1)*math.cos(lat2)*dd2;
 var p2 = math.pow(2, d2);
 var d3 = math.sqrt(p1 + p2);
 var as4 = asin(d3);
 var das4rad = 2*as4;
 var das4nm = das4rad*180*60/math.pi;
 return das4nm;
} # calcGPSDist

###############################################################################
# calculate great circle true course using radians and distance in nm.
#=============================================================================#
var calcGPSTrueCourse = func (d, lat1, lon1, lat2, lon2) {
  var tc1 = 0;
  if(math.sin(lon2-lon1)<0) {      
   tc1=acos((math.sin(lat2)-math.sin(lat1)*math.cos(d))/(math.sin(d)*math.cos(lat1)));
  }
  else {   
   var d1 = (math.sin(lat2)-math.sin(lat1)*math.cos(d));
   var d2 = (math.sin(d)*math.cos(lat1));
   var dd1 = d1 / d2;
   tc1=2*math.pi - math.acos(dd1);
  }
  return tc1;
} # calcGPSTrueCourse

###############################################################################
#  calculate a coord as 'dest' that is d distance from a reference 
#  position(lat1,lon1) along a true course tc in radians
#=============================================================================#
var calcDistCoord = func (tc, d, lat1, lon1) {
  var RAD2DEG = 57.29577951;
 
  var lat = math.asin(math.sin(lat1)*math.cos(d)+math.cos(lat1)*math.sin(d)*math.cos(tc));
  var dlon = math.atan2(math.sin(tc)*math.sin(d)*math.cos(lat1),math.cos(d)-math.sin(lat1)*math.sin(lat));
  var lon = math.mod(lon1-dlon+math.pi,2*math.pi )-math.pi;
  var latDeg = lat*RAD2DEG;
  var lonDeg = lon*RAD2DEG;
  var dest = geo.Coord.new();
  dest.set_latlon(latDeg, lonDeg, 0);
  return dest;
} # calcDistCoord

var calcDistCoordDeg = func(tc, d, lat1, lon1) {
  var DEG2RAD = 0.01745329;
  return calcDistCoord(tc*DEG2RAD, nm2rad(d), (lat1*DEG2RAD), (lon1*DEG2RAD));
} # calcDistCoordDeg

###############################################################################
# calc straight line course between two GPS coords
#=============================================================================#
var calcGPSCourse = func(lat1, lon1, lat2, lon2) {
  var DEG2RAD = 0.01745329;
  lat1 *= DEG2RAD;
  lon1 *= DEG2RAD;
  lat2 *= DEG2RAD;
  lon2 *= DEG2RAD;

 var sin_lat1 = math.sin(lat1);
 var cos_lat1 = math.cos(lat1);
 var sin_lat2 = math.sin(lat2);
 var cos_lat2 = math.cos(lat2);
 var dlon = lon2-lon1;
   
 var Aorth = math.atan2(math.sin(dlon)*cos_lat2, cos_lat1*sin_lat2-sin_lat1*cos_lat2*math.cos(dlon));
 var TWOPI=6.28318530;
 var RAD2DEG = 57.29577951;
 while ( Aorth >= TWOPI ) {Aorth -= TWOPI};
 if(Aorth<0) Aorth+= TWOPI;
 return (Aorth*RAD2DEG);
} # calcGPSCourse

var asin = func(x) {
  math.atan2(x,math.sqrt(math.pow(2,1-x)));
}

Interesting insight. Lookign at the original GPL code, a similar comment can be made. Now to evolve this version - awexome

Question: DEG2RAD factor (and others)

Do you intentionally replicate the DEG2RAD in each function in order to prevent it from being mutated if it is a "global" DEG2RAD constant? What about turning the DEG2RAD factor into a function that simply returns the constant. What do you think? There's tons of Nasal code replicating all those constants... I do know that people do this to ensure that they are using the right constants (i.e. there are not static variables in Nasal, so things can be changed arbitrarily). I guess it would be "better" to eventually move such constants to a separate namespace and "protect" it from being mutated by using some "globals" magic, so that these symbols can no longer be overwritten.--Hooray 16:40, 10 April 2012 (EDT)