JSBSim Flight Dynamics Model 1.0 (23 February 2013)
An Open Source Flight Dynamics and Control Software Library in C++

FGFunction Class Reference

Represents a mathematical function. More...

#include <FGFunction.h>

Inheritance diagram for FGFunction:
Collaboration diagram for FGFunction:

List of all members.

Public Member Functions

 FGFunction (FGPropertyManager *PropertyManager, Element *element, const std::string &prefix="")
 Constructor.
virtual ~FGFunction ()
 Destructor.
void cacheValue (bool shouldCache)
 Specifies whether to cache the value of the function, so it is calculated only once per frame.
std::string GetName (void) const
 Retrieves the name of the function.
double GetValue (void) const
 Retrieves the value of the function object.
std::string GetValueAsString (void) const
 The value that the function evaluates to, as a string.

Detailed Description

The FGFunction class is a powerful and versatile resource that allows algebraic functions to be defined in a JSBSim configuration file. It is similar in concept to MathML (Mathematical Markup Language, www.w3.org/Math/), but simpler and more terse. A function definition consists of an operation, a value, a table, or a property (which evaluates to a value). The currently supported operations are:

  • sum (takes n args)
  • difference (takes n args)
  • product (takes n args)
  • quotient (takes 2 args)
  • pow (takes 2 args)
  • sqrt (takes one argument)
  • toradians (takes one argument)
  • todegrees (takes one argument)
  • exp (takes 2 args)
  • log2 (takes 1 arg)
  • ln (takes 1 arg)
  • log10 (takes 1 arg)
  • abs (takes n args)
  • sin (takes 1 arg)
  • cos (takes 1 arg)
  • tan (takes 1 arg)
  • asin (takes 1 arg)
  • acos (takes 1 arg)
  • atan (takes 1 arg)
  • atan2 (takes 2 args)
  • min (takes n args)
  • max (takes n args)
  • avg (takes n args)
  • fraction
  • mod
  • lt (less than, takes 2 args)
  • le (less equal, takes 2 args)
  • gt (greater than, takes 2 args)
  • ge (greater than, takes 2 args)
  • eq (equal, takes 2 args)
  • nq (not equal, takes 2 args)
  • and (takes n args)
  • or (takes n args)
  • not (takes 1 args)
  • if-then (takes 2-3 args)
  • switch (takes 2 or more args)
  • random (Gaussian distribution random number)
  • urandom (Uniform random number between -1 and +1)
  • pi
  • integer
  • interpolate 1-dimensional (takes a minimum of five arguments, odd number)

An operation is defined in the configuration file as in the following example:

  <sum>
    <value> 3.14159 </value>
    <property> velocities/qbar </property>
    <product>
      <value> 0.125 </value>
      <property> metrics/wingarea </property>
    </product>
  </sum>

A full function definition, such as is used in the aerodynamics section of a configuration file includes the function element, and other elements. It should be noted that there can be only one non-optional (non-documentation) element - that is, one operation element - in the top-level function definition. Multiple value and/or property elements cannot be immediate child members of the function element. Almost always, the first operation within the function element will be a product or sum. For example:

<function name="aero/moment/Clr">
    <description>Roll moment due to yaw rate</description>
    <product>
        <property>aero/qbar-area</property>
        <property>metrics/bw-ft</property>
        <property>aero/bi2vel</property>
        <property>velocities/r-aero-rad_sec</property>
        <table>
            <independentVar>aero/alpha-rad</independentVar>
            <tableData>
                 0.000  0.08
                 0.094  0.19
            </tableData>
        </table>
    </product>
</function>

The "lowest level" in a function is always a value or a property, which cannot itself contain another element. As shown, operations can contain values, properties, tables, or other operations. In the first above example, the sum element contains all three. What is evaluated is written algebraically as:

 3.14159 + qbar + (0.125 * wingarea) 

Some operations can take only a single argument. That argument, however, can be an operation (such as sum) which can contain other items. The point to keep in mind is that it evaluates to a single value - which is just what the trigonometric functions require (except atan2, which takes two arguments).

Specific Function Definitions

Note: In the definitions below, a "property" refers to a single property specified within either the <property></property> tag or the shortcut tag, <p></p>. The keyword "value" refers to a single numeric value specified either within the <value></value> tag or the shortcut <v></v> tag. The keyword "table" refers to a single table specified either within the <table></table> tag or the shortcut <t></t> tag. The plural form of any of the three words refers to one or more instances of a property, value, or table.

  • sum, sums the values of all immediate child elements:
        <sum>
          {properties, values, tables, or other function elements}
        </sum>
    
        Example: Mach + 0.01
    
        <sum>
          <p> velocities/mach </p>
          <v> 0.01 </v>
        </sum>
    
  • difference, subtracts the values of all immediate child elements from the value of the first child element:
        <difference>
          {properties, values, tables, or other function elements}
        </difference>
    
        Example: Mach - 0.01
    
        <difference>
          <p> velocities/mach </p>
          <v> 0.01 </v>
        </difference>
    
  • product multiplies together the values of all immediate child elements:
        <product>
          {properties, values, tables, or other function elements}
        </product>
    
        Example: qbar*S*beta*CY_beta
    
        <product>
          <property> aero/qbar-psf            </property>
          <property> metrics/Sw-sqft          </property>
          <property> aero/beta-rad            </property>
          <property> aero/coefficient/CY_beta </property>
        </product>
    
  • quotient, divides the value of the first immediate child element by the second immediate child element:
        <quotient>
          {property, value, table, or other function element}
          {property, value, table, or other function element}
        </quotient>
    
        Example: (2*GM)/R
    
        <quotient>
          <product>
            <v> 2.0 </v>
            <p> guidance/executive/gm </p>
          </product>
          <p> position/radius-to-vehicle-ft </p>
        </quotient>
    
  • pow, raises the value of the first immediate child element to the power of the value of the second immediate child element:
        <pow>
          {property, value, table, or other function element}
          {property, value, table, or other function element}
        </pow>
    
        Example: Mach^2
    
        <pow>
          <p> velocities/mach </p>
          <v> 2.0 </v>
        </pow>
    
  • sqrt, takes the square root of the value of the immediate child element:
        <sqrt>
          {property, value, table, or other function element}
        </sqrt>
    
        Example: square root of 25
    
        <sqrt> <v> 25.0 </v> </sqrt>
    
  • toradians, converts a presumed argument in degrees to radians by multiplying the value of the immediate child element by pi/180:
        <toradians>
          {property, value, table, or other function element}
        </toradians>
    
        Example: convert 45 degrees to radians
    
        <toradians> <v> 45 </v> </toradians>
    
  • todegrees, converts a presumed argument in radians to degrees by multiplying the value of the immediate child element by 180/pi:
        <todegrees>
          {property, value, table, or other function element}
        </todegrees>
    
        Example: convert 0.5*pi radians to degrees
    
        <todegrees>
          <product> <v> 0.5 </v> <pi/> </product>
        </todegrees>
    
  • exp, raises "e" to the power of the immediate child element:
        <exp>
          {property, value, table, or other function element}
        </exp>
    
        Example: raise "e" to the 1.5 power, e^1.5
    
        <exp> <v> 1.5 </v> </exp>
    
  • log2, calculates the log base 2 value of the immediate child element:
        <log2>
          {property, value, table, or other function element} 
        </log2>
    
        Example:
        <log2> <v> 128 </v> </log2>
    
  • ln, calculates the natural logarithm of the value of the immediate child element:
        <ln>
          {property, value, table, or other function element}
        </ln>
        
        Example: ln(128)
    
        <ln> <v> 200 </v> </ln>
    
  • log10 calculates the base 10 logarithm of the value of the immediate child element
        <log10>
          {property, value, table, or other function element}
        </log10>
    
        Example log(Mach)
    
        <log10> <p> velocities/mach </p> </log10>
    
  • abs calculates the absolute value of the immediate child element
        <abs>
          {property, value, table, or other function element}
        </abs>
    
        Example:
    
        <abs> <p> flight-path/gamma-rad </p> </abs>
    
  • sin calculates the sine of the value of the immediate child element (the argument is expected to be in radians)
        <sin>
          {property, value, table, or other function element}
        </sin>
    
        Example:
    
        <sin> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </sin>
    
  • cos calculates the cosine of the value of the immediate child element (the argument is expected to be in radians)
        <cos>
          {property, value, table, or other function element}
        </cos>
    
        Example:
    
        <cos> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </cos>
    
  • tan calculates the tangent of the value of the immediate child element (the argument is expected to be in radians)
        <tan>
          {property, value, table, or other function element}
        </tan>
    
        Example:
    
        <tan> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </tan>
    
  • asin calculates the arcsine (inverse sine) of the value of the immediate child element. The value provided should be in the range from -1 to +1. The value returned will be expressed in radians, and will be in the range from -pi/2 to +pi/2.
        <asin>
          {property, value, table, or other function element}
        </asin>
    
        Example:
    
        <asin> <v> 0.5 </v> </asin>
    
  • acos calculates the arccosine (inverse cosine) of the value of the immediate child element. The value provided should be in the range from -1 to +1. The value returned will be expressed in radians, and will be in the range from 0 to pi.
        <acos>
          {property, value, table, or other function element}
        </acos>
    
        Example:
    
        <acos> <v> 0.5 </v> </acos>
    
  • atan calculates the inverse tangent of the value of the immediate child element. The value returned will be expressed in radians, and will be in the range from -pi/2 to +pi/2.
        <atan>
          {property, value, table, or other function element}
        </atan>
    
        Example:
    
        <atan> <v> 0.5 </v> </atan>
    
  • atan2 calculates the inverse tangent of the value of the immediate child elements, Y/X (in that order). It even works for X values near zero. The value returned will be expressed in radians, and in the range -pi to +pi.
        <atan2>
          {property, value, table, or other function element} {property, value, table, or other function element}
        </atan2>
    
        Example: inverse tangent of 0.5/0.25, evaluates to: 1.107 radians
    
        <atan2> <v> 0.5 </<v> <v> 0.25 </v> </atan2>
    
  • min returns the smallest value from all the immediate child elements
        <min>
          {properties, values, tables, or other function elements}
        </min>
        
        Example: returns the lesser of velocity and 2500
    
        <min>
          <p> velocities/eci-velocity-mag-fps </p>
          <v> 2500.0 </v>
        </min>
    
  • max returns the largest value from all the immediate child elements
        <max>
          {properties, values, tables, or other function elements}
        </max>
        
        Example: returns the greater of velocity and 15000
    
        <max>
          <p> velocities/eci-velocity-mag-fps </p>
          <v> 15000.0 </v>
        </max>
    
  • avg returns the average value of all the immediate child elements
        <avg>
          {properties, values, tables, or other function elements} 
        </avg>
    
        Example: returns the average of the four numbers below, evaluates to 0.50.
    
        <avg>
          <v> 0.25 </v>
          <v> 0.50 </v>
          <v> 0.75 </v>
          <v> 0.50 </v>
        </avg>
    
  • fraction returns the fractional part of the value of the immediate child element
        <fraction>
          {property, value, table, or other function element}
        </fraction>
    
        Example: returns the fractional part of pi - or, roughly, 0.1415926...
    
        <fraction> <pi/> </fraction>
    
  • integer returns the integer portion of the value of the immediate child element
        <integer>
          {property, value, table, or other function element}
        </integer>
    
  • mod returns the remainder from the integer division of the value of the first immediate child element by the second immediate child element, X/Y (X modulo Y). The value returned is the value X-I*Y, for the largest integer I such that if Y is nonzero, the result has the same sign as X and magnitude less than the magnitude of Y. For instance, the expression "5 mod 2" would evaluate to 1 because 5 divided by 2 leaves a quotient of 2 and a remainder of 1, while "9 mod 3" would evaluate to 0 because the division of 9 by 3 has a quotient of 3 and leaves a remainder of 0.
        <mod>
          {property, value, table, or other function element} {property, value, table, or other function element}
        </mod>
    
        Example: 5 mod 2, evaluates to 1
    
        <mod> <v> 5 </v> <v> 2 </v> </mod>
    
  • lt returns a 1 if the value of the first immediate child element is less than the value of the second immediate child element, returns 0 otherwise
        <lt>
          {property, value, table, or other function element}
          {property, value, table, or other function element}
        </lt>
    
        Example: returns 1 if thrust is less than 10,000, returns 0 otherwise
    
        <lt>
          <p> propulsion/engine[2]/thrust-lbs </p>
          <v> 10000.0 </v>
        </lt>
    
  • le returns a 1 if the value of the first immediate child element is less than or equal to the value of the second immediate child element, returns 0 otherwise
        <le>
          {property, value, table, or other function element}
          {property, value, table, or other function element}
        </le>
    
        Example: returns 1 if thrust is less than or equal to 10,000, returns 0 otherwise
    
        <le>
          <p> propulsion/engine[2]/thrust-lbs </p>
          <v> 10000.0 </v>
        </le>
    
  • gt returns a 1 if the value of the first immediate child element is greater than the value of the second immediate child element, returns 0 otherwise
        <gt>
          {property, value, table, or other function element}
          {property, value, table, or other function element}
        </gt>
    
        Example: returns 1 if thrust is greater than 10,000, returns 0 otherwise
    
        <gt>
          <p> propulsion/engine[2]/thrust-lbs </p>
          <v> 10000.0 </v>
        </gt>
    
  • ge returns a 1 if the value of the first immediate child element is greater than or equal to the value of the second immediate child element, returns 0 otherwise
        <ge>
          {property, value, table, or other function element}
          {property, value, table, or other function element}
        </ge>
    
        Example: returns 1 if thrust is greater than or equal to 10,000, returns 0 otherwise
    
        <ge>
          <p> propulsion/engine[2]/thrust-lbs </p>
          <v> 10000.0 </v>
        </ge>
    
  • eq returns a 1 if the value of the first immediate child element is equal to the second immediate child element, returns 0 otherwise
        <eq>
          {property, value, table, or other function element}
          {property, value, table, or other function element}
        </eq>
    
        Example: returns 1 if thrust is equal to 10,000, returns 0 otherwise
    
        <eq>
          <p> propulsion/engine[2]/thrust-lbs </p>
          <v> 10000.0 </v>
        </eq>
    
  • nq returns a 1 if the value of the first immediate child element is not equal to the value of the second immediate child element, returns 0 otherwise
        <nq>
          {property, value, table, or other function element}
          {property, value, table, or other function element}
        </nq>
    
        Example: returns 1 if thrust is not 0, returns 0 otherwise
    
        <nq>
          <p> propulsion/engine[2]/thrust-lbs </p>
          <v> 0.0 </v>
        </nq>
    
  • and returns a 1 if the values of the immediate child elements are all 1, returns 0 otherwise. Values provided are expected to be either 1 or 0 within machine precision.
        <and>
          {properties, values, tables, or other function elements}
        </and>
    
        Example: returns 1 if the specified flags are all 1
    
        <and>
          <p> guidance/first-stage-flight-flag </p>
          <p> control/engines-running-flag </p>
        </and>
    
  • or returns a 1 if the values of any of the immediate child elements 1, returns 0 otherwise. Values provided are expected to be either 1 or 0 within machine precision.
        <or>
          {properties, values, tables, or other function elements}
        </or>
    
        Example: returns 1 if any of the specified flags are 1
    
        <or>
          <p> guidance/first-stage-flight-flag </p>
          <p> control/engines-running-flag </p>
        </or>
    
  • not returns the inverse of the value of the supplied immediate child element (e.g., returns 1 if supplied a 0)
        <not>
          {property, value, table, or other function element} 
        </not>
    
        Example: returns 0 if the value of the supplied flag is 1
    
        <not> <p> guidance/first-stage-flight-flag </p> </not>
    
  • ifthen if the value of the first immediate child element is 1, then the value of the second immediate child element is returned, otherwise the value of the third child element is returned
         <ifthen>
           {property, value, table, or other function element}
           {property, value, table, or other function element}
           {property, value, table, or other function element}
         </ifthen>
    
         Example: if flight-mode is greater than 2, then a value of 0.00 is returned, 
                  otherwise the value of the property control/pitch-lag is returned.
    
         <ifthen>
           <gt> <p> executive/flight-mode </p> <v> 2 </v> </gt>
           <v> 0.00 </v>
           <p> control/pitch-lag </p>
         </ifthen>
    
  • switch uses the integer value of the first immediate child element as an index to select one of the subsequent immediate child elements to return the value of
         <switch>
           {property, value, table, or other function element}
           {property, value, table, or other function element}
           {property, value, table, or other function element}
           ...
         </switch>
    
         Example: if flight-mode is 2, the switch function returns 0.50
    
         <switch>
           <p> executive/flight-mode </p>
           <v> 0.25 </v>
           <v> 0.50 </v>
           <v> 0.75 </v>
           <v> 1.00 </v>
         </switch>
    
  • random Takes no arguments and returns a Gaussian distributed random number
     <random/> 
    
  • urandom Takes no arguments and returns a uniformly distributed random number between -1 and +1
     <urandom/>
    
  • pi Takes no argument and returns the value of Pi
     <pi/>
    
  • interpolate1d returns the result from a 1-dimensional interpolation of the supplied values, with the value of the first immediate child element representing the lookup value into the table, and the following pairs of values representing the independent and dependent values. The first provided child element is expected to be a property. The interpolation does not extrapolate, but holds the highest value if the provided lookup value goes outside of the provided range.
         <interpolate1d>
           {property, value, table, or other function element}
           {property, value, table, or other function element} {property, value, table, or other function element}
           ...
         </interpolate1d>
    
         Example: If mach is 0.4, the interpolation will return 0.375. If mach is 1.5, the interpolation
                  will return 0.60.
    
         <interpolate1d>
           <p> velocities/mach </p>
           <v> 0.00 </v>  <v> 0.25 </v>
           <v> 0.80 </v>  <v> 0.50 </v>
           <v> 0.90 </v>  <v> 0.60 </v>
           </interpolate1d>
    
    Author:
    Jon Berndt

Definition at line 699 of file FGFunction.h.


Constructor & Destructor Documentation

FGFunction ( FGPropertyManager PropertyManager,
Element element,
const std::string &  prefix = "" 
)

When this constructor is called, the XML element pointed to in memory by the element argument is traversed. If other FGParameter-derived objects (values, functions, properties, or tables) are encountered, this instance of the FGFunction object will store a pointer to the found object and pass the relevant Element pointer to the constructor for the new object. In other words, each FGFunction object maintains a list of "child" FGParameter-derived objects which in turn may each contain its own list, and so on. At runtime, each object evaluates its child parameters, which each may have its own child parameters to evaluate.

Parameters:
PropertyManagera pointer to the property manager instance.
elementa pointer to the Element object containing the function definition.
prefixan optional prefix to prepend to the name given to the property that represents this function (if given).

Definition at line 111 of file FGFunction.cpp.

References FGJSBBase::fgcyan, FGJSBBase::fgred, Element::GetAttributeValue(), Element::GetDataAsNumber(), Element::GetDataLine(), Element::GetElement(), Element::GetName(), Element::GetNextElement(), FGJSBBase::highint, and FGJSBBase::reset.

                                      : PropertyManager(propMan), Prefix(prefix)
{
  Element* element;
  string operation, property_name;
  cached = false;
  cachedValue = -HUGE_VAL;
  invlog2val = 1.0/log10(2.0);
  pCopyTo = 0L;

  Name = el->GetAttributeValue("name");
  operation = el->GetName();

  if (operation == function_string) {
    sCopyTo = el->GetAttributeValue("copyto");
    if (!sCopyTo.empty()) {
      pCopyTo = PropertyManager->GetNode(sCopyTo);
      if (pCopyTo == 0L) cerr << "Property \"" << sCopyTo << "\" must be previously defined in function "
                              << Name << endl;
    }
    Type = eTopLevel;
  } else if (operation == product_string) {
    Type = eProduct;
  } else if (operation == difference_string) {
    Type = eDifference;
  } else if (operation == sum_string) {
    Type = eSum;
  } else if (operation == quotient_string) {
    Type = eQuotient;
  } else if (operation == pow_string) {
    Type = ePow;
  } else if (operation == sqrt_string) {
    Type = eSqrt;
  } else if (operation == toradians_string) {
    Type = eToRadians;
  } else if (operation == todegrees_string) {
    Type = eToDegrees;
  } else if (operation == log2_string) {
    Type = eLog2;
  } else if (operation == ln_string) {
    Type = eLn;
  } else if (operation == log10_string) {
    Type = eLog10;
  } else if (operation == abs_string) {
    Type = eAbs;
  } else if (operation == sign_string) {
    Type = eSign;
  } else if (operation == sin_string) {
    Type = eSin;
  } else if (operation == exp_string) {
    Type = eExp;
  } else if (operation == cos_string) {
    Type = eCos;
  } else if (operation == tan_string) {
    Type = eTan;
  } else if (operation == asin_string) {
    Type = eASin;
  } else if (operation == acos_string) {
    Type = eACos;
  } else if (operation == atan_string) {
    Type = eATan;
  } else if (operation == atan2_string) {
    Type = eATan2;
  } else if (operation == min_string) {
    Type = eMin;
  } else if (operation == max_string) {
    Type = eMax;
  } else if (operation == avg_string) {
    Type = eAvg;
  } else if (operation == fraction_string) {
    Type = eFrac;
  } else if (operation == integer_string) {
    Type = eInteger;
  } else if (operation == mod_string) {
    Type = eMod;
  } else if (operation == random_string) {
    Type = eRandom;
  } else if (operation == urandom_string) {
    Type = eUrandom;
  } else if (operation == pi_string) {
    Type = ePi;
  } else if (operation == rotation_alpha_local_string) {
    Type = eRotation_alpha_local;
  } else if (operation == rotation_beta_local_string) {
    Type = eRotation_beta_local;
  } else if (operation == rotation_gamma_local_string) {
    Type = eRotation_gamma_local;
  } else if (operation == rotation_bf_to_wf_string) {
    Type = eRotation_bf_to_wf;
  } else if (operation == rotation_wf_to_bf_string) {
    Type = eRotation_wf_to_bf;
  } else if (operation == lessthan_string) {
    Type = eLT;
  } else if (operation == lessequal_string) {
    Type = eLE;
  } else if (operation == greatthan_string) {
    Type = eGT;
  } else if (operation == greatequal_string) {
    Type = eGE;
  } else if (operation == equal_string) {
    Type = eEQ;
  } else if (operation == notequal_string) {
    Type = eNE;
  } else if (operation == and_string) {
    Type = eAND;
  } else if (operation == or_string) {
    Type = eOR;
  } else if (operation == not_string) {
    Type = eNOT;
  } else if (operation == ifthen_string) {
    Type = eIfThen;
  } else if (operation == switch_string) {
    Type = eSwitch;
  } else if (operation == interpolate1d_string) {
    Type = eInterpolate1D;
  } else if (operation != description_string) {
    cerr << "Bad operation " << operation << " detected in configuration file" << endl;
  }

  element = el->GetElement();
  if (!element && Type != eRandom && Type != eUrandom && Type != ePi) {
    cerr << fgred << highint << endl;
    cerr << "  No element was specified as an argument to the \"" << operation << "\" operation" << endl;
    cerr << "  This can happen when, for instance, a cos operation is specified and a " << endl;
    cerr << "  property name is given explicitly, but is not placed within a" << endl;
    cerr << "  <property></property> element tag pair." << endl;
    cerr << reset;
    exit(-2);
  }
  
  while (element) {
    operation = element->GetName();

    // data types
    if (operation == property_string || operation == p_string) {
      property_name = element->GetDataLine();
      if (property_name.find("#") != string::npos) {
        if (is_number(Prefix)) {
          property_name = replace(property_name,"#",Prefix);
        }
      }
      FGPropertyNode* newNode = 0L;
      if (PropertyManager->HasNode(property_name)) {
        newNode = PropertyManager->GetNode(property_name);
        Parameters.push_back(new FGPropertyValue( newNode ));
      } else {
        cerr << fgcyan << "Warning: The property " + property_name + " is initially undefined."
             << reset << endl;
        Parameters.push_back(new FGPropertyValue( property_name,
                                                  PropertyManager ));
      }
    } else if (operation == value_string || operation == v_string) {
      Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
    } else if (operation == table_string || operation == t_string) {
      Parameters.push_back(new FGTable(PropertyManager, element));
    // operations
    } else if (operation == product_string ||
               operation == difference_string ||
               operation == sum_string ||
               operation == quotient_string ||
               operation == pow_string ||
               operation == sqrt_string ||
               operation == toradians_string ||
               operation == todegrees_string ||
               operation == exp_string ||
               operation == log2_string ||
               operation == ln_string ||
               operation == log10_string ||
               operation == abs_string ||
               operation == sign_string ||
               operation == sin_string ||
               operation == cos_string ||
               operation == tan_string ||
               operation == asin_string ||
               operation == acos_string ||
               operation == atan_string ||
               operation == atan2_string ||
               operation == min_string ||
               operation == max_string ||
               operation == fraction_string ||
               operation == integer_string ||
               operation == mod_string ||
               operation == random_string ||
               operation == urandom_string ||
               operation == pi_string ||
               operation == avg_string ||
               operation == rotation_alpha_local_string||
               operation == rotation_beta_local_string||
               operation == rotation_gamma_local_string||
               operation == rotation_bf_to_wf_string||
               operation == rotation_wf_to_bf_string ||
               operation == lessthan_string ||
               operation == lessequal_string ||
               operation == greatthan_string ||
               operation == greatequal_string ||
               operation == equal_string ||
               operation == notequal_string ||
               operation == and_string ||
               operation == or_string ||
               operation == not_string ||
               operation == ifthen_string ||
               operation == switch_string ||
               operation == interpolate1d_string)
    {
      Parameters.push_back(new FGFunction(PropertyManager, element, Prefix));
    } else if (operation != description_string) {
      cerr << "Bad operation " << operation << " detected in configuration file" << endl;
    }
    element = el->GetNextElement();
  }

  bind(); // Allow any function to save its value

  Debug(0);
}

Here is the call graph for this function:


Member Function Documentation

void cacheValue ( bool  shouldCache)

If shouldCache is true, then the value of the function is calculated, and a flag is set so further calculations done this frame will use the cached value. In order to turn off caching, cacheValue must be called with a false argument.

Parameters:
shouldCachespecifies whether the function should cache the computed value.

Definition at line 336 of file FGFunction.cpp.

References FGFunction::GetValue().

{
  cached = false; // Must set cached to false prior to calling GetValue(), else
                  // it will _never_ calculate the value;
  if (cache) {
    cachedValue = GetValue();
    cached = true;
  }
}

Here is the call graph for this function:

double GetValue ( void  ) const [virtual]
Returns:
the total value of the function.

Implements FGParameter.

Definition at line 360 of file FGFunction.cpp.

Referenced by FGFunction::cacheValue(), FGRocket::Calculate(), FGBallonet::Calculate(), FGRocket::FGRocket(), FGFunction::GetValueAsString(), and FGAerodynamics::Run().

{
  unsigned int i;
  double scratch;
  double temp=0;

  if (cached) return cachedValue;

  if (   Type != eRandom
      && Type != eUrandom
      && Type != ePi      ) temp = Parameters[0]->GetValue();
  
  switch (Type) {
  case eTopLevel:
    if (pCopyTo) pCopyTo->setDoubleValue(temp);
    break;
  case eProduct:
    for (i=1;i<Parameters.size();i++) {
      temp *= Parameters[i]->GetValue();
    }
    break;
  case eSum:
    for (i=1;i<Parameters.size();i++) {
      temp += Parameters[i]->GetValue();
    }
    break;
  case eQuotient:
    if (Parameters[1]->GetValue() != 0.0)
      temp /= Parameters[1]->GetValue();
    else
      temp = HUGE_VAL;
    break;
  case eDifference:
    for (i=1;i<Parameters.size();i++) {
      temp -= Parameters[i]->GetValue();
    }
    break;
  case ePow:
    temp = pow(temp,Parameters[1]->GetValue());
    break;
  case eSqrt:
    temp = sqrt(temp);
    break;
  case eToRadians:
    temp *= M_PI/180.0;
    break;
  case eToDegrees:
    temp *= 180.0/M_PI;
    break;
  case eExp:
    temp = exp(temp);
    break;
  case eLog2:
    if (temp > 0.00) temp = log10(temp)*invlog2val;
    else temp = -HUGE_VAL;
    break;
  case eLn:
    if (temp > 0.00) temp = log(temp);
    else temp = -HUGE_VAL;
    break;
  case eLog10:
    if (temp > 0.00) temp = log10(temp);
    else temp = -HUGE_VAL;
    break;
  case eAbs:
    temp = fabs(temp);
    break;
  case eSign:
    temp =  temp < 0 ? -1:1; // 0.0 counts as positive.
    break;
  case eSin:
    temp = sin(temp);
    break;
  case eCos:
    temp = cos(temp);
    break;
  case eTan:
    temp = tan(temp);
    break;
  case eACos:
    temp = acos(temp);
    break;
  case eASin:
    temp = asin(temp);
    break;
  case eATan:
    temp = atan(temp);
    break;
  case eATan2:
    temp = atan2(temp, Parameters[1]->GetValue());
    break;
  case eMod:
    temp = ((int)temp) % ((int) Parameters[1]->GetValue());
    break;
  case eMin:
    for (i=1;i<Parameters.size();i++) {
      if (Parameters[i]->GetValue() < temp) temp = Parameters[i]->GetValue();
    }    
    break;
  case eMax:
    for (i=1;i<Parameters.size();i++) {
      if (Parameters[i]->GetValue() > temp) temp = Parameters[i]->GetValue();
    }    
    break;
  case eAvg:
    for (i=1;i<Parameters.size();i++) {
      temp += Parameters[i]->GetValue();
    }
    temp /= Parameters.size();
    break;
  case eFrac:
    temp = modf(temp, &scratch);
    break;
  case eInteger:
    modf(temp, &scratch);
    temp = scratch;
    break;
  case eRandom:
    temp = GaussianRandomNumber();
    break;
  case eUrandom:
    temp = -1.0 + (((double)rand()/double(RAND_MAX))*2.0);
    break;
  case ePi:
    temp = M_PI;
    break;
  case eLT:
    temp = (temp < Parameters[1]->GetValue())?1:0;
    break;
  case eLE:
    temp = (temp <= Parameters[1]->GetValue())?1:0;
    break;
  case eGT:
    temp = (temp > Parameters[1]->GetValue())?1:0;
    break;
  case eGE:
    temp = (temp >= Parameters[1]->GetValue())?1:0;
    break;
  case eEQ:
    temp = (temp == Parameters[1]->GetValue())?1:0;
    break;
  case eNE:
    temp = (temp != Parameters[1]->GetValue())?1:0;
    break;
  case eAND:
    {
      bool flag = (GetBinary(temp) != 0u);
      for (i=1; i<Parameters.size() && flag; i++) {
        flag = (GetBinary(Parameters[i]->GetValue()) != 0);
      }
      temp = flag ? 1 : 0;
    }
    break;
  case eOR:
    {
      bool flag = (GetBinary(temp) != 0);
      for (i=1; i<Parameters.size() && !flag; i++) {
        flag = (GetBinary(Parameters[i]->GetValue()) != 0);
      }
      temp = flag ? 1 : 0;
    }
    break;
  case eNOT:
    temp = (GetBinary(temp) != 0) ? 0 : 1;
    break;
  case eIfThen:
    {
      i = Parameters.size();
      if (i == 3) {
        if (GetBinary(temp) == 1) {
          temp = Parameters[1]->GetValue();
        } else {
          temp = Parameters[2]->GetValue();
        }
      } else {
        throw("Malformed if/then function statement");
      }
    }
    break;
  case eSwitch:
    {
      unsigned int n = Parameters.size()-1;
      i = int(temp+0.5);
      if (i >= 0u && i < n) {
        temp = Parameters[i+1]->GetValue();
      } else {
        throw(string("The switch function index selected a value above the range of supplied values"
                     " - not enough values were supplied."));
      }
    }
    break;
  case eInterpolate1D:
    {
      unsigned int sz = Parameters.size();
      if (temp <= Parameters[1]->GetValue()) {
        temp = Parameters[2]->GetValue();
      } else if (temp >= Parameters[sz-2]->GetValue()) {
        temp = Parameters[sz-1]->GetValue();
      } else {
        for (unsigned int i=1; i<=sz-4; i+=2) {
          if (temp < Parameters[i+2]->GetValue()) {
            double factor = (temp - Parameters[i]->GetValue()) /
                            (Parameters[i+2]->GetValue() - Parameters[i]->GetValue());
            double span = Parameters[i+3]->GetValue() - Parameters[i+1]->GetValue();
            double val = factor*span;
            temp = Parameters[i+1]->GetValue() + val;
            break;
          }
        }
      }
    }
    break;
  case eRotation_alpha_local:
    if (Parameters.size()==6) // calculates local angle of attack for skydiver body component
        //Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
    {
        double alpha = Parameters[0]->GetValue()*degtorad;
        double beta = Parameters[1]->GetValue()*degtorad;
        double gamma = Parameters[2]->GetValue()*degtorad;
        double phi = Parameters[3]->GetValue()*degtorad;
        double theta = Parameters[4]->GetValue()*degtorad;
        double psi = Parameters[5]->GetValue()*degtorad;
        double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
        double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
        double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
        double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
        double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
        //calculate local body frame to the intermediate body frame rotation quaternion
        double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
        double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
        double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
        double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
        //calculate the intermediate body frame to global wind frame rotation quaternion
        double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
        double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
        double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
        double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
        //multiply quaternions
        double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
        double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
        double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
        double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
        //calculate alpha_local
        temp = -atan2(2*(Cy*Ct-Cx*Cz),(Ct*Ct+Cx*Cx-Cy*Cy-Cz*Cz));
        temp *= radtodeg;
    } else {
      temp = 1;
    }
    break;
  case eRotation_beta_local:
    if (Parameters.size()==6) // calculates local angle of sideslip for skydiver body component
        //Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
    {
        double alpha = Parameters[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
        double beta = Parameters[1]->GetValue()*degtorad;  //sideslip angle of intermediate body frame
        double gamma = Parameters[2]->GetValue()*degtorad; //roll angle of intermediate body frame
        double phi = Parameters[3]->GetValue()*degtorad;   //x-axis Euler angle from the intermediate body frame to the local body frame
        double theta = Parameters[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
        double psi = Parameters[5]->GetValue()*degtorad;   //z-axis Euler angle from the intermediate body frame to the local body frame
        double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
        double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
        double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
        double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
        double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
        //calculate local body frame to the intermediate body frame rotation quaternion
        double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
        double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
        double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
        double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
        //calculate the intermediate body frame to global wind frame rotation quaternion
        double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
        double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
        double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
        double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
        //multiply quaternions
        double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
        double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
        double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
        double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
        //calculate beta_local
        temp = asin(2*(Cx*Cy+Cz*Ct));
        temp *= radtodeg;
    }
    else // 
    {temp = 1;}
    break;
  case eRotation_gamma_local:
    if (Parameters.size()==6) // calculates local angle of attack for skydiver body component
        //Euler angles from the intermediate body frame to the local body frame must be from a z-y-x axis rotation order
        {
        double alpha = Parameters[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
        double beta = Parameters[1]->GetValue()*degtorad;  //sideslip angle of intermediate body frame
        double gamma = Parameters[2]->GetValue()*degtorad; //roll angle of intermediate body frame
        double phi = Parameters[3]->GetValue()*degtorad;   //x-axis Euler angle from the intermediate body frame to the local body frame
        double theta = Parameters[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
        double psi = Parameters[5]->GetValue()*degtorad;   //z-axis Euler angle from the intermediate body frame to the local body frame
        double cphi2 = cos(-phi/2), ctht2 = cos(-theta/2), cpsi2 = cos(-psi/2);
        double sphi2 = sin(-phi/2), stht2 = sin(-theta/2), spsi2 = sin(-psi/2);
        double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
        double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
        double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
        //calculate local body frame to the intermediate body frame rotation quaternion
        double At = cphi2*ctht2*cpsi2 - sphi2*stht2*spsi2;
        double Ax = cphi2*stht2*spsi2 + sphi2*ctht2*cpsi2;
        double Ay = cphi2*stht2*cpsi2 - sphi2*ctht2*spsi2;
        double Az = cphi2*ctht2*spsi2 + sphi2*stht2*cpsi2;
        //calculate the intermediate body frame to global wind frame rotation quaternion
        double Bt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
        double Bx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
        double By = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
        double Bz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
        //multiply quaternions
        double Ct = At*Bt - Ax*Bx - Ay*By - Az*Bz;
        double Cx = At*Bx + Ax*Bt + Ay*Bz - Az*By;
        double Cy = At*By - Ax*Bz + Ay*Bt + Az*Bx;
        double Cz = At*Bz + Ax*By - Ay*Bx + Az*Bt;
        //calculate local roll anlge
        temp = -atan2(2*(Cx*Ct-Cz*Cy),(Ct*Ct-Cx*Cx+Cy*Cy-Cz*Cz));
        temp *= radtodeg;
    }
    else // 
    {temp = 1;}
    break;
  case eRotation_bf_to_wf:
    if (Parameters.size()==7) // transforms the input vector from a body frame to a wind frame.  The origin of the vector remains the same.
    {
        double rx = Parameters[0]->GetValue();             //x component of input vector
        double ry = Parameters[1]->GetValue();             //y component of input vector
        double rz = Parameters[2]->GetValue();             //z component of input vector
        double alpha = Parameters[3]->GetValue()*degtorad; //angle of attack of the body frame
        double beta = Parameters[4]->GetValue()*degtorad;  //sideslip angle of the body frame
        double gamma = Parameters[5]->GetValue()*degtorad; //roll angle of the body frame
        double index = Parameters[6]->GetValue();
        double calpha2 = cos(-alpha/2), salpha2 = sin(-alpha/2);
        double cbeta2 = cos(beta/2), sbeta2 = sin(beta/2);
        double cgamma2 = cos(-gamma/2), sgamma2 = sin(-gamma/2);
        //calculate the body frame to wind frame quaternion
        double qt = calpha2*cbeta2*cgamma2 - salpha2*sbeta2*sgamma2;
        double qx = calpha2*cbeta2*sgamma2 + salpha2*sbeta2*cgamma2;
        double qy = calpha2*sbeta2*sgamma2 + salpha2*cbeta2*cgamma2;
        double qz = calpha2*sbeta2*cgamma2 - salpha2*cbeta2*sgamma2;
        //calculate the quaternion conjugate
        double qstart = qt;
        double qstarx = -qx;
        double qstary = -qy;
        double qstarz = -qz;
        //multiply quaternions v*q
        double vqt = -rx*qx - ry*qy - rz*qz;
        double vqx =  rx*qt + ry*qz - rz*qy;
        double vqy = -rx*qz + ry*qt + rz*qx;
        double vqz =  rx*qy - ry*qx + rz*qt;
        //multiply quaternions qstar*vq
        double Cx = qstart*vqx + qstarx*vqt + qstary*vqz - qstarz*vqy;
        double Cy = qstart*vqy - qstarx*vqz + qstary*vqt + qstarz*vqx;
        double Cz = qstart*vqz + qstarx*vqy - qstary*vqx + qstarz*vqt;

        if (index == 1)     temp = Cx;
        else if (index ==2) temp = Cy;
        else                temp = Cz;
    }
    else // 
    {temp = 1;}
    break;
  case eRotation_wf_to_bf:
    if (Parameters.size()==7) // transforms the input vector from q wind frame to a body frame.  The origin of the vector remains the same.
    {
        double rx = Parameters[0]->GetValue();             //x component of input vector
        double ry = Parameters[1]->GetValue();             //y component of input vector
        double rz = Parameters[2]->GetValue();             //z component of input vector
        double alpha = Parameters[3]->GetValue()*degtorad; //angle of attack of the body frame
        double beta = Parameters[4]->GetValue()*degtorad;  //sideslip angle of the body frame
        double gamma = Parameters[5]->GetValue()*degtorad; //roll angle of the body frame
        double index = Parameters[6]->GetValue();
        double calpha2 = cos(alpha/2), salpha2 = sin(alpha/2);
        double cbeta2 = cos(-beta/2), sbeta2 = sin(-beta/2);
        double cgamma2 = cos(gamma/2), sgamma2 = sin(gamma/2);
        //calculate the wind frame to body frame quaternion
        double qt =  cgamma2*cbeta2*calpha2 + sgamma2*sbeta2*salpha2;
        double qx = -cgamma2*sbeta2*salpha2 + sgamma2*cbeta2*calpha2;
        double qy =  cgamma2*cbeta2*salpha2 - sgamma2*sbeta2*calpha2;
        double qz =  cgamma2*sbeta2*calpha2 + sgamma2*cbeta2*salpha2;
        //calculate the quaternion conjugate
        double qstart =  qt;
        double qstarx = -qx;
        double qstary = -qy;
        double qstarz = -qz;
        //multiply quaternions v*q
        double vqt = -rx*qx - ry*qy - rz*qz;
        double vqx =  rx*qt + ry*qz - rz*qy;
        double vqy = -rx*qz + ry*qt + rz*qx;
        double vqz =  rx*qy - ry*qx + rz*qt;
        //multiply quaternions qstar*vq
        double Cx = qstart*vqx + qstarx*vqt + qstary*vqz - qstarz*vqy;
        double Cy = qstart*vqy - qstarx*vqz + qstary*vqt + qstarz*vqx;
        double Cz = qstart*vqz + qstarx*vqy - qstary*vqx + qstarz*vqt;

        if (index == 1)     temp = Cx;
        else if (index ==2) temp = Cy;
        else                temp = Cz;
    }
    else // 
    {temp = 1;}
    break;
  default:
    cerr << "Unknown function operation type" << endl;
    break;
  }

  return temp;
}

Here is the caller graph for this function:

string GetValueAsString ( void  ) const
Returns:
the value of the function as a string.

Definition at line 773 of file FGFunction.cpp.

References FGFunction::GetValue().

{
  ostringstream buffer;

  buffer << setw(9) << setprecision(6) << GetValue();
  return buffer.str();
}

Here is the call graph for this function:


The documentation for this class was generated from the following files: