]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/math/FGFunction.cpp
Merge branch 'vivian/trainz'
[flightgear.git] / src / FDM / JSBSim / math / FGFunction.cpp
index b655d3b374d854332e863272cdfc9b90a19c6a23..e45e6d9aa23c1a14181e4a9371fb2f2f9ad9e44b 100755 (executable)
@@ -5,16 +5,41 @@ Author: Jon Berndt
 Date started: 8/25/2004
 Purpose: Stores various parameter types for functions
 
+ ------------- Copyright (C) 2004  Jon S. Berndt (jon@jsbsim.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ 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 Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA  02111-1307, USA.
+
+ Further information about the GNU Lesser General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 INCLUDES
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-#include <stdio.h>
-
+#include <sstream>
+#include <iomanip>
+#include <cstdlib>
+#include <cmath>
 #include "FGFunction.h"
 #include "FGTable.h"
 #include "FGPropertyValue.h"
 #include "FGRealValue.h"
+#include "input_output/FGXMLElement.h"
+#include "input_output/FGPropertyManager.h"
+
+using namespace std;
 
 namespace JSBSim {
 
@@ -25,57 +50,122 @@ static const char *IdHdr = ID_FUNCTION;
 CLASS IMPLEMENTATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
+FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& prefix)
                                       : PropertyManager(propMan), Prefix(prefix)
 {
-  int i;
   Element* element;
   string operation, property_name;
-  int size = el->GetNumElements();
   cached = false;
   cachedValue = -HUGE_VAL;
+  invlog2val = 1.0/log10(2.0);
+
+  property_string = "property";
+  value_string = "value";
+  table_string = "table";
+  p_string = "p";
+  v_string = "v";
+  t_string = "t";
+
+  function_string = "function";
+  description_string = "description";
+  sum_string = "sum";
+  difference_string = "difference";
+  product_string = "product";
+  quotient_string = "quotient";
+  pow_string = "pow";
+  exp_string = "exp";
+  log2_string = "log2";
+  ln_string = "ln";
+  log10_string = "log10";
+  abs_string = "abs";
+  sin_string = "sin";
+  cos_string = "cos";
+  tan_string = "tan";
+  asin_string = "asin";
+  acos_string = "acos";
+  atan_string = "atan";
+  atan2_string = "atan2";
+  min_string = "min";
+  max_string = "max";
+  avg_string = "avg";
+  fraction_string = "fraction";
+  mod_string = "mod";
+  random_string = "random";
+  integer_string = "integer";
 
   Name = el->GetAttributeValue("name");
   operation = el->GetName();
-  if (operation == string("function")) {
+
+  if (operation == function_string) {
     Type = eTopLevel;
-    bind();
-  } else if (operation == string("product")) {
+  } else if (operation == product_string) {
     Type = eProduct;
-  } else if (operation == string("difference")) {
+  } else if (operation == difference_string) {
     Type = eDifference;
-  } else if (operation == string("sum")) {
+  } else if (operation == sum_string) {
     Type = eSum;
-  } else if (operation == string("quotient")) {
+  } else if (operation == quotient_string) {
     Type = eQuotient;
-  } else if (operation == string("pow")) {
+  } else if (operation == pow_string) {
     Type = ePow;
-  } else if (operation == string("abs")) {
+  } 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 == string("sin")) {
+  } else if (operation == sin_string) {
     Type = eSin;
-  } else if (operation == string("cos")) {
+  } else if (operation == exp_string) {
+    Type = eExp;
+  } else if (operation == cos_string) {
     Type = eCos;
-  } else if (operation == string("tan")) {
+  } else if (operation == tan_string) {
     Type = eTan;
-  } else if (operation == string("asin")) {
+  } else if (operation == asin_string) {
     Type = eASin;
-  } else if (operation == string("acos")) {
+  } else if (operation == acos_string) {
     Type = eACos;
-  } else if (operation == string("atan")) {
+  } else if (operation == atan_string) {
     Type = eATan;
-  } else if (operation == string("atan2")) {
+  } else if (operation == atan2_string) {
     Type = eATan2;
-  } else if (operation != string("description")) {
+  } 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 != description_string) {
     cerr << "Bad operation " << operation << " detected in configuration file" << endl;
   }
 
   element = el->GetElement();
+  if (!element) {
+    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 == string("property")) {
+    if (operation == property_string || operation == p_string) {
       property_name = element->GetDataLine();
       FGPropertyManager* newNode = PropertyManager->GetNode(property_name);
       if (newNode == 0) {
@@ -84,32 +174,45 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
       } else {
         Parameters.push_back(new FGPropertyValue( newNode ));
       }
-    } else if (operation == string("value")) {
+    } else if (operation == value_string || operation == v_string) {
       Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
-    } else if (operation == string("table")) {
+    } else if (operation == table_string || operation == t_string) {
       Parameters.push_back(new FGTable(PropertyManager, element));
     // operations
-    } else if (operation == string("product") ||
-               operation == string("difference") ||
-               operation == string("sum") ||
-               operation == string("quotient") ||
-               operation == string("pow") ||
-               operation == string("abs") ||
-               operation == string("sin") ||
-               operation == string("cos") ||
-               operation == string("tan") ||
-               operation == string("asin") ||
-               operation == string("acos") ||
-               operation == string("atan") ||
-               operation == string("atan2"))
+    } else if (operation == product_string ||
+               operation == difference_string ||
+               operation == sum_string ||
+               operation == quotient_string ||
+               operation == pow_string ||
+               operation == exp_string ||
+               operation == log2_string ||
+               operation == ln_string ||
+               operation == log10_string ||
+               operation == abs_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 == avg_string )
     {
       Parameters.push_back(new FGFunction(PropertyManager, element));
-    } else if (operation != string("description")) {
+    } 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);
 }
 
@@ -117,8 +220,7 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
 
 FGFunction::~FGFunction(void)
 {
-  string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
-  PropertyManager->Untie(tmp);
+  for (unsigned int i=0; i<Parameters.size(); i++) delete Parameters[i];
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -137,7 +239,8 @@ void FGFunction::cacheValue(bool cache)
 
 double FGFunction::GetValue(void) const
 {
-  int i;
+  unsigned int i;
+  double scratch;
 
   if (cached) return cachedValue;
 
@@ -147,13 +250,19 @@ double FGFunction::GetValue(void) const
   case eTopLevel:
     break;
   case eProduct:
-    for (i=1;i<Parameters.size();i++) temp *= Parameters[i]->GetValue();
+    for (i=1;i<Parameters.size();i++) {
+      temp *= Parameters[i]->GetValue();
+    }
     break;
   case eDifference:
-    for (i=1;i<Parameters.size();i++) temp -= Parameters[i]->GetValue();
+    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();
+    for (i=1;i<Parameters.size();i++) {
+      temp += Parameters[i]->GetValue();
+    }
     break;
   case eQuotient:
     temp /= Parameters[1]->GetValue();
@@ -161,6 +270,21 @@ double FGFunction::GetValue(void) const
   case ePow:
     temp = pow(temp,Parameters[1]->GetValue());
     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;
@@ -185,6 +309,35 @@ double FGFunction::GetValue(void) const
   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;
   default:
     cerr << "Unknown function operation type" << endl;
     break;
@@ -197,12 +350,10 @@ double FGFunction::GetValue(void) const
 
 string FGFunction::GetValueAsString(void) const
 {
-  char buffer[20];
-  string value;
+  ostringstream buffer;
 
-  sprintf(buffer,"%9.6f",GetValue());
-  value = string(buffer);
-  return value;
+  buffer << setw(9) << setprecision(6) << GetValue();
+  return buffer.str();
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -210,7 +361,12 @@ string FGFunction::GetValueAsString(void) const
 void FGFunction::bind(void)
 {
   if ( !Name.empty() ) {
-    string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
+    string tmp;
+    if (Prefix.empty())
+      tmp  = PropertyManager->mkPropertyName(Name, false); // Allow upper case
+    else
+      tmp  = PropertyManager->mkPropertyName(Prefix + "/" + Name, false); // Allow upper case
+
     PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
   }
 }
@@ -245,8 +401,8 @@ void FGFunction::Debug(int from)
     }
   }
   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
-    if (from == 0) cout << "Instantiated: FGGroundReactions" << endl;
-    if (from == 1) cout << "Destroyed:    FGGroundReactions" << endl;
+    if (from == 0) cout << "Instantiated: FGFunction" << endl;
+    if (from == 1) cout << "Destroyed:    FGFunction" << endl;
   }
   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
   }