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 {
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();
- Parameters.push_back(new FGPropertyValue(PropertyManager->GetNode(property_name)));
- } else if (operation == string("value")) {
+ FGPropertyManager* newNode = PropertyManager->GetNode(property_name);
+ if (newNode == 0) {
+ cerr << "The property " << property_name << " is undefined." << endl;
+ abort();
+ } else {
+ Parameters.push_back(new FGPropertyValue( newNode ));
+ }
+ } 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);
}
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];
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGFunction::GetValue(void) const
{
- int i;
+ unsigned int i;
+ double scratch;
if (cached) return cachedValue;
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();
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 = abs(temp);
+ temp = fabs(temp);
break;
case eSin:
temp = sin(temp);
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;
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();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
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);
}
}
}
}
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
}