1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5 Date started: 8/25/2004
6 Purpose: Stores various parameter types for functions
8 ------------- Copyright (C) 2004 Jon S. Berndt (jon@jsbsim.org) -------------
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 You should have received a copy of the GNU Lesser General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 Place - Suite 330, Boston, MA 02111-1307, USA.
24 Further information about the GNU Lesser General Public License can also be found on
25 the world wide web at http://www.gnu.org.
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
35 #include "FGFunction.h"
37 #include "FGPropertyValue.h"
38 #include "FGRealValue.h"
39 #include "input_output/FGXMLElement.h"
40 #include "input_output/FGPropertyManager.h"
46 static const char *IdSrc = "$Id: FGFunction.cpp,v 1.35 2010/08/28 12:41:56 jberndt Exp $";
47 static const char *IdHdr = ID_FUNCTION;
49 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
53 FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& prefix)
54 : PropertyManager(propMan), Prefix(prefix)
57 string operation, property_name;
59 cachedValue = -HUGE_VAL;
60 invlog2val = 1.0/log10(2.0);
62 property_string = "property";
63 value_string = "value";
64 table_string = "table";
69 function_string = "function";
70 description_string = "description";
72 difference_string = "difference";
73 product_string = "product";
74 quotient_string = "quotient";
79 log10_string = "log10";
87 atan2_string = "atan2";
91 fraction_string = "fraction";
93 random_string = "random";
94 integer_string = "integer";
96 Name = el->GetAttributeValue("name");
97 operation = el->GetName();
99 if (operation == function_string) {
101 } else if (operation == product_string) {
103 } else if (operation == difference_string) {
105 } else if (operation == sum_string) {
107 } else if (operation == quotient_string) {
109 } else if (operation == pow_string) {
111 } else if (operation == log2_string) {
113 } else if (operation == ln_string) {
115 } else if (operation == log10_string) {
117 } else if (operation == abs_string) {
119 } else if (operation == sin_string) {
121 } else if (operation == exp_string) {
123 } else if (operation == cos_string) {
125 } else if (operation == tan_string) {
127 } else if (operation == asin_string) {
129 } else if (operation == acos_string) {
131 } else if (operation == atan_string) {
133 } else if (operation == atan2_string) {
135 } else if (operation == min_string) {
137 } else if (operation == max_string) {
139 } else if (operation == avg_string) {
141 } else if (operation == fraction_string) {
143 } else if (operation == integer_string) {
145 } else if (operation == mod_string) {
147 } else if (operation == random_string) {
149 } else if (operation != description_string) {
150 cerr << "Bad operation " << operation << " detected in configuration file" << endl;
153 element = el->GetElement();
155 cerr << fgred << highint << endl;
156 cerr << " No element was specified as an argument to the \"" << operation << "\" operation" << endl;
157 cerr << " This can happen when, for instance, a cos operation is specified and a " << endl;
158 cerr << " property name is given explicitly, but is not placed within a" << endl;
159 cerr << " <property></property> element tag pair." << endl;
165 operation = element->GetName();
168 if (operation == property_string || operation == p_string) {
169 property_name = element->GetDataLine();
170 if (property_name.find("#") != string::npos) {
171 if (is_number(Prefix)) {
172 property_name = replace(property_name,"#",Prefix);
175 FGPropertyManager* newNode = 0L;
176 if (PropertyManager->HasNode(property_name)) {
177 newNode = PropertyManager->GetNode(property_name);
178 Parameters.push_back(new FGPropertyValue( newNode ));
180 cerr << fgcyan << "The property " + property_name + " is initially undefined."
182 Parameters.push_back(new FGPropertyValue( property_name ));
184 } else if (operation == value_string || operation == v_string) {
185 Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
186 } else if (operation == table_string || operation == t_string) {
187 Parameters.push_back(new FGTable(PropertyManager, element));
189 } else if (operation == product_string ||
190 operation == difference_string ||
191 operation == sum_string ||
192 operation == quotient_string ||
193 operation == pow_string ||
194 operation == exp_string ||
195 operation == log2_string ||
196 operation == ln_string ||
197 operation == log10_string ||
198 operation == abs_string ||
199 operation == sin_string ||
200 operation == cos_string ||
201 operation == tan_string ||
202 operation == asin_string ||
203 operation == acos_string ||
204 operation == atan_string ||
205 operation == atan2_string ||
206 operation == min_string ||
207 operation == max_string ||
208 operation == fraction_string ||
209 operation == integer_string ||
210 operation == mod_string ||
211 operation == random_string ||
212 operation == avg_string )
214 Parameters.push_back(new FGFunction(PropertyManager, element, Prefix));
215 } else if (operation != description_string) {
216 cerr << "Bad operation " << operation << " detected in configuration file" << endl;
218 element = el->GetNextElement();
221 bind(); // Allow any function to save its value
226 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
228 FGFunction::~FGFunction(void)
230 for (unsigned int i=0; i<Parameters.size(); i++) delete Parameters[i];
233 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
235 void FGFunction::cacheValue(bool cache)
237 cached = false; // Must set cached to false prior to calling GetValue(), else
238 // it will _never_ calculate the value;
240 cachedValue = GetValue();
245 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 double FGFunction::GetValue(void) const
253 if (cached) return cachedValue;
256 temp = Parameters[0]->GetValue();
257 } catch (string prop) {
258 if (PropertyManager->HasNode(prop)) {
259 ((FGPropertyValue*)Parameters[0])->SetNode(PropertyManager->GetNode(prop));
260 temp = Parameters[0]->GetValue();
262 throw("Property " + prop + " was not defined anywhere.");
270 for (i=1;i<Parameters.size();i++) {
271 temp *= Parameters[i]->GetValue();
275 for (i=1;i<Parameters.size();i++) {
276 temp -= Parameters[i]->GetValue();
280 for (i=1;i<Parameters.size();i++) {
281 temp += Parameters[i]->GetValue();
285 if (Parameters[1]->GetValue() != 0.0)
286 temp /= Parameters[1]->GetValue();
291 temp = pow(temp,Parameters[1]->GetValue());
297 if (temp > 0.00) temp = log10(temp)*invlog2val;
298 else temp = -HUGE_VAL;
301 if (temp > 0.00) temp = log(temp);
302 else temp = -HUGE_VAL;
305 if (temp > 0.00) temp = log10(temp);
306 else temp = -HUGE_VAL;
330 temp = atan2(temp, Parameters[1]->GetValue());
333 temp = ((int)temp) % ((int) Parameters[1]->GetValue());
336 for (i=1;i<Parameters.size();i++) {
337 if (Parameters[i]->GetValue() < temp) temp = Parameters[i]->GetValue();
341 for (i=1;i<Parameters.size();i++) {
342 if (Parameters[i]->GetValue() > temp) temp = Parameters[i]->GetValue();
346 for (i=1;i<Parameters.size();i++) {
347 temp += Parameters[i]->GetValue();
349 temp /= Parameters.size();
352 temp = modf(temp, &scratch);
355 modf(temp, &scratch);
359 temp = GaussianRandomNumber();
362 cerr << "Unknown function operation type" << endl;
369 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371 string FGFunction::GetValueAsString(void) const
373 ostringstream buffer;
375 buffer << setw(9) << setprecision(6) << GetValue();
379 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
381 void FGFunction::bind(void)
383 if ( !Name.empty() ) {
386 tmp = PropertyManager->mkPropertyName(Name, false);
388 if (is_number(Prefix)) {
389 if (Name.find("#") != string::npos) { // if "#" is found
390 Name = replace(Name,"#",Prefix);
391 tmp = PropertyManager->mkPropertyName(Name, false);
393 cerr << "Malformed function name with number: " << Prefix
394 << " and property name: " << Name
395 << " but no \"#\" sign for substitution." << endl;
398 tmp = PropertyManager->mkPropertyName(Prefix + "/" + Name, false);
402 PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
406 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407 // The bitmasked value choices are as follows:
408 // unset: In this case (the default) JSBSim would only print
409 // out the normally expected messages, essentially echoing
410 // the config files as they are read. If the environment
411 // variable is not set, debug_lvl is set to 1 internally
412 // 0: This requests JSBSim not to output any messages
414 // 1: This value explicity requests the normal JSBSim
416 // 2: This value asks for a message to be printed out when
417 // a class is instantiated
418 // 4: When this value is set, a message is displayed when a
419 // FGModel object executes its Run() method
420 // 8: When this value is set, various runtime state variables
421 // are printed out periodically
422 // 16: When set various parameters are sanity checked and
423 // a message is printed out when they go out of bounds
425 void FGFunction::Debug(int from)
427 if (debug_lvl <= 0) return;
429 if (debug_lvl & 1) { // Standard console startup message output
430 if (from == 0) { // Constructor
431 if (Type == eTopLevel)
432 cout << " Function: " << Name << endl;
435 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
436 if (from == 0) cout << "Instantiated: FGFunction" << endl;
437 if (from == 1) cout << "Destroyed: FGFunction" << endl;
439 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
441 if (debug_lvl & 8 ) { // Runtime state variables
443 if (debug_lvl & 16) { // Sanity checking
445 if (debug_lvl & 64) {
446 if (from == 0) { // Constructor
447 cout << IdSrc << endl;
448 cout << IdHdr << endl;