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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
33 #include "FGFunction.h"
35 #include "FGPropertyValue.h"
36 #include "FGRealValue.h"
40 static const char *IdSrc = "$Id$";
41 static const char *IdHdr = ID_FUNCTION;
43 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
45 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
47 FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
48 : PropertyManager(propMan), Prefix(prefix)
51 string operation, property_name;
52 int size = el->GetNumElements();
54 cachedValue = -HUGE_VAL;
56 property_string = "property";
57 value_string = "value";
58 table_string = "table";
63 function_string = "function";
64 description_string = "description";
66 difference_string = "difference";
67 product_string = "product";
68 quotient_string = "quotient";
78 atan2_string = "atan2";
82 fraction_string = "fraction";
84 random_string = "random";
85 integer_string = "integer";
87 Name = el->GetAttributeValue("name");
88 operation = el->GetName();
90 if (operation == function_string) {
92 } else if (operation == product_string) {
94 } else if (operation == difference_string) {
96 } else if (operation == sum_string) {
98 } else if (operation == quotient_string) {
100 } else if (operation == pow_string) {
102 } else if (operation == abs_string) {
104 } else if (operation == sin_string) {
106 } else if (operation == exp_string) {
108 } else if (operation == cos_string) {
110 } else if (operation == tan_string) {
112 } else if (operation == asin_string) {
114 } else if (operation == acos_string) {
116 } else if (operation == atan_string) {
118 } else if (operation == atan2_string) {
120 } else if (operation == min_string) {
122 } else if (operation == max_string) {
124 } else if (operation == avg_string) {
126 } else if (operation == fraction_string) {
128 } else if (operation == integer_string) {
130 } else if (operation == mod_string) {
132 } else if (operation == random_string) {
134 } else if (operation != description_string) {
135 cerr << "Bad operation " << operation << " detected in configuration file" << endl;
138 element = el->GetElement();
140 cerr << fgred << highint << endl;
141 cerr << " No element was specified as an argument to the \"" << operation << "\" operation" << endl;
142 cerr << " This can happen when, for instance, a cos operation is specified and a " << endl;
143 cerr << " property name is given explicitly, but is not placed within a" << endl;
144 cerr << " <property></property> element tag pair." << endl;
150 operation = element->GetName();
153 if (operation == property_string || operation == p_string) {
154 property_name = element->GetDataLine();
155 FGPropertyManager* newNode = PropertyManager->GetNode(property_name);
157 cerr << "The property " << property_name << " is undefined." << endl;
160 Parameters.push_back(new FGPropertyValue( newNode ));
162 } else if (operation == value_string || operation == v_string) {
163 Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
164 } else if (operation == table_string || operation == t_string) {
165 Parameters.push_back(new FGTable(PropertyManager, element));
167 } else if (operation == product_string ||
168 operation == difference_string ||
169 operation == sum_string ||
170 operation == quotient_string ||
171 operation == pow_string ||
172 operation == exp_string ||
173 operation == abs_string ||
174 operation == sin_string ||
175 operation == cos_string ||
176 operation == tan_string ||
177 operation == asin_string ||
178 operation == acos_string ||
179 operation == atan_string ||
180 operation == atan2_string ||
181 operation == min_string ||
182 operation == max_string ||
183 operation == fraction_string ||
184 operation == integer_string ||
185 operation == mod_string ||
186 operation == random_string ||
187 operation == avg_string )
189 Parameters.push_back(new FGFunction(PropertyManager, element));
190 } else if (operation != description_string) {
191 cerr << "Bad operation " << operation << " detected in configuration file" << endl;
193 element = el->GetNextElement();
196 bind(); // Allow any function to save its value
201 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
203 FGFunction::~FGFunction(void)
205 for (unsigned int i=0; i<Parameters.size(); i++) delete Parameters[i];
208 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210 void FGFunction::cacheValue(bool cache)
212 cached = false; // Must set cached to false prior to calling GetValue(), else
213 // it will _never_ calculate the value;
215 cachedValue = GetValue();
220 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222 double FGFunction::GetValue(void) const
227 if (cached) return cachedValue;
229 double temp = Parameters[0]->GetValue();
235 for (i=1;i<Parameters.size();i++) {
236 temp *= Parameters[i]->GetValue();
240 for (i=1;i<Parameters.size();i++) {
241 temp -= Parameters[i]->GetValue();
245 for (i=1;i<Parameters.size();i++) {
246 temp += Parameters[i]->GetValue();
250 temp /= Parameters[1]->GetValue();
253 temp = pow(temp,Parameters[1]->GetValue());
280 temp = atan2(temp, Parameters[1]->GetValue());
283 temp = ((int)temp) % ((int) Parameters[1]->GetValue());
286 for (i=1;i<Parameters.size();i++) {
287 if (Parameters[i]->GetValue() < temp) temp = Parameters[i]->GetValue();
291 for (i=1;i<Parameters.size();i++) {
292 if (Parameters[i]->GetValue() > temp) temp = Parameters[i]->GetValue();
296 for (i=1;i<Parameters.size();i++) {
297 temp += Parameters[i]->GetValue();
299 temp /= Parameters.size();
302 temp = modf(temp, &scratch);
305 modf(temp, &scratch);
309 temp = GaussianRandomNumber();
312 cerr << "Unknown function operation type" << endl;
319 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321 string FGFunction::GetValueAsString(void) const
326 sprintf(buffer,"%9.6f",GetValue());
327 value = string(buffer);
331 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333 void FGFunction::bind(void)
335 if ( !Name.empty() ) {
336 string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
337 PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
341 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
342 // The bitmasked value choices are as follows:
343 // unset: In this case (the default) JSBSim would only print
344 // out the normally expected messages, essentially echoing
345 // the config files as they are read. If the environment
346 // variable is not set, debug_lvl is set to 1 internally
347 // 0: This requests JSBSim not to output any messages
349 // 1: This value explicity requests the normal JSBSim
351 // 2: This value asks for a message to be printed out when
352 // a class is instantiated
353 // 4: When this value is set, a message is displayed when a
354 // FGModel object executes its Run() method
355 // 8: When this value is set, various runtime state variables
356 // are printed out periodically
357 // 16: When set various parameters are sanity checked and
358 // a message is printed out when they go out of bounds
360 void FGFunction::Debug(int from)
362 if (debug_lvl <= 0) return;
364 if (debug_lvl & 1) { // Standard console startup message output
365 if (from == 0) { // Constructor
366 if (Type == eTopLevel)
367 cout << " Function: " << Name << endl;
370 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
371 if (from == 0) cout << "Instantiated: FGFunction" << endl;
372 if (from == 1) cout << "Destroyed: FGFunction" << endl;
374 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
376 if (debug_lvl & 8 ) { // Runtime state variables
378 if (debug_lvl & 16) { // Sanity checking
380 if (debug_lvl & 64) {
381 if (from == 0) { // Constructor
382 cout << IdSrc << endl;
383 cout << IdHdr << endl;