]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/math/FGFunction.cpp
Sync. w. JSBSim cvs
[flightgear.git] / src / FDM / JSBSim / math / FGFunction.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGFunction.cpp
4 Author: Jon Berndt
5 Date started: 8/25/2004
6 Purpose: Stores various parameter types for functions
7
8  ------------- Copyright (C) 2004  Jon S. Berndt (jon@jsbsim.org) -------------
9
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
13  version.
14
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
18  details.
19
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.
23
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.
26
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28 INCLUDES
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
30
31 #include <sstream>
32 #include <iomanip>
33 #include <cstdlib>
34 #include "FGFunction.h"
35 #include "FGTable.h"
36 #include "FGPropertyValue.h"
37 #include "FGRealValue.h"
38 #include "input_output/FGXMLElement.h"
39 #include "input_output/FGPropertyManager.h"
40
41 using namespace std;
42
43 namespace JSBSim {
44
45 static const char *IdSrc = "$Id$";
46 static const char *IdHdr = ID_FUNCTION;
47
48 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49 CLASS IMPLEMENTATION
50 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
51
52 FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& prefix)
53                                       : PropertyManager(propMan), Prefix(prefix)
54 {
55   Element* element;
56   string operation, property_name;
57   cached = false;
58   cachedValue = -HUGE_VAL;
59
60   property_string = "property";
61   value_string = "value";
62   table_string = "table";
63   p_string = "p";
64   v_string = "v";
65   t_string = "t";
66
67   function_string = "function";
68   description_string = "description";
69   sum_string = "sum";
70   difference_string = "difference";
71   product_string = "product";
72   quotient_string = "quotient";
73   pow_string = "pow";
74   exp_string = "exp";
75   abs_string = "abs";
76   sin_string = "sin";
77   cos_string = "cos";
78   tan_string = "tan";
79   asin_string = "asin";
80   acos_string = "acos";
81   atan_string = "atan";
82   atan2_string = "atan2";
83   min_string = "min";
84   max_string = "max";
85   avg_string = "avg";
86   fraction_string = "fraction";
87   mod_string = "mod";
88   random_string = "random";
89   integer_string = "integer";
90
91   Name = el->GetAttributeValue("name");
92   operation = el->GetName();
93
94   if (operation == function_string) {
95     Type = eTopLevel;
96   } else if (operation == product_string) {
97     Type = eProduct;
98   } else if (operation == difference_string) {
99     Type = eDifference;
100   } else if (operation == sum_string) {
101     Type = eSum;
102   } else if (operation == quotient_string) {
103     Type = eQuotient;
104   } else if (operation == pow_string) {
105     Type = ePow;
106   } else if (operation == abs_string) {
107     Type = eAbs;
108   } else if (operation == sin_string) {
109     Type = eSin;
110   } else if (operation == exp_string) {
111     Type = eExp;
112   } else if (operation == cos_string) {
113     Type = eCos;
114   } else if (operation == tan_string) {
115     Type = eTan;
116   } else if (operation == asin_string) {
117     Type = eASin;
118   } else if (operation == acos_string) {
119     Type = eACos;
120   } else if (operation == atan_string) {
121     Type = eATan;
122   } else if (operation == atan2_string) {
123     Type = eATan2;
124   } else if (operation == min_string) {
125     Type = eMin;
126   } else if (operation == max_string) {
127     Type = eMax;
128   } else if (operation == avg_string) {
129     Type = eAvg;
130   } else if (operation == fraction_string) {
131     Type = eFrac;
132   } else if (operation == integer_string) {
133     Type = eInteger;
134   } else if (operation == mod_string) {
135     Type = eMod;
136   } else if (operation == random_string) {
137     Type = eRandom;
138   } else if (operation != description_string) {
139     cerr << "Bad operation " << operation << " detected in configuration file" << endl;
140   }
141
142   element = el->GetElement();
143   if (!element) {
144     cerr << fgred << highint << endl;
145     cerr << "  No element was specified as an argument to the \"" << operation << "\" operation" << endl;
146     cerr << "  This can happen when, for instance, a cos operation is specified and a " << endl;
147     cerr << "  property name is given explicitly, but is not placed within a" << endl;
148     cerr << "  <property></property> element tag pair." << endl;
149     cerr << reset;
150     exit(-2);
151   }
152   
153   while (element) {
154     operation = element->GetName();
155
156     // data types
157     if (operation == property_string || operation == p_string) {
158       property_name = element->GetDataLine();
159       FGPropertyManager* newNode = PropertyManager->GetNode(property_name);
160       if (newNode == 0) {
161         cerr << "The property " << property_name << " is undefined." << endl;
162         abort();
163       } else {
164         Parameters.push_back(new FGPropertyValue( newNode ));
165       }
166     } else if (operation == value_string || operation == v_string) {
167       Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
168     } else if (operation == table_string || operation == t_string) {
169       Parameters.push_back(new FGTable(PropertyManager, element));
170     // operations
171     } else if (operation == product_string ||
172                operation == difference_string ||
173                operation == sum_string ||
174                operation == quotient_string ||
175                operation == pow_string ||
176                operation == exp_string ||
177                operation == abs_string ||
178                operation == sin_string ||
179                operation == cos_string ||
180                operation == tan_string ||
181                operation == asin_string ||
182                operation == acos_string ||
183                operation == atan_string ||
184                operation == atan2_string ||
185                operation == min_string ||
186                operation == max_string ||
187                operation == fraction_string ||
188                operation == integer_string ||
189                operation == mod_string ||
190                operation == random_string ||
191                operation == avg_string )
192     {
193       Parameters.push_back(new FGFunction(PropertyManager, element));
194     } else if (operation != description_string) {
195       cerr << "Bad operation " << operation << " detected in configuration file" << endl;
196     }
197     element = el->GetNextElement();
198   }
199
200   bind(); // Allow any function to save its value
201
202   Debug(0);
203 }
204
205 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
206
207 FGFunction::~FGFunction(void)
208 {
209   for (unsigned int i=0; i<Parameters.size(); i++) delete Parameters[i];
210 }
211
212 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213
214 void FGFunction::cacheValue(bool cache)
215 {
216   cached = false; // Must set cached to false prior to calling GetValue(), else
217                   // it will _never_ calculate the value;
218   if (cache) {
219     cachedValue = GetValue();
220     cached = true;
221   }
222 }
223
224 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225
226 double FGFunction::GetValue(void) const
227 {
228   unsigned int i;
229   double scratch;
230
231   if (cached) return cachedValue;
232
233   double temp = Parameters[0]->GetValue();
234
235   switch (Type) {
236   case eTopLevel:
237     break;
238   case eProduct:
239     for (i=1;i<Parameters.size();i++) {
240       temp *= Parameters[i]->GetValue();
241     }
242     break;
243   case eDifference:
244     for (i=1;i<Parameters.size();i++) {
245       temp -= Parameters[i]->GetValue();
246     }
247     break;
248   case eSum:
249     for (i=1;i<Parameters.size();i++) {
250       temp += Parameters[i]->GetValue();
251     }
252     break;
253   case eQuotient:
254     temp /= Parameters[1]->GetValue();
255     break;
256   case ePow:
257     temp = pow(temp,Parameters[1]->GetValue());
258     break;
259   case eExp:
260     temp = exp(temp);
261     break;
262   case eAbs:
263     temp = fabs(temp);
264     break;
265   case eSin:
266     temp = sin(temp);
267     break;
268   case eCos:
269     temp = cos(temp);
270     break;
271   case eTan:
272     temp = tan(temp);
273     break;
274   case eACos:
275     temp = acos(temp);
276     break;
277   case eASin:
278     temp = asin(temp);
279     break;
280   case eATan:
281     temp = atan(temp);
282     break;
283   case eATan2:
284     temp = atan2(temp, Parameters[1]->GetValue());
285     break;
286   case eMod:
287     temp = ((int)temp) % ((int) Parameters[1]->GetValue());
288     break;
289   case eMin:
290     for (i=1;i<Parameters.size();i++) {
291       if (Parameters[i]->GetValue() < temp) temp = Parameters[i]->GetValue();
292     }    
293     break;
294   case eMax:
295     for (i=1;i<Parameters.size();i++) {
296       if (Parameters[i]->GetValue() > temp) temp = Parameters[i]->GetValue();
297     }    
298     break;
299   case eAvg:
300     for (i=1;i<Parameters.size();i++) {
301       temp += Parameters[i]->GetValue();
302     }
303     temp /= Parameters.size();
304     break;
305   case eFrac:
306     temp = modf(temp, &scratch);
307     break;
308   case eInteger:
309     modf(temp, &scratch);
310     temp = scratch;
311     break;
312   case eRandom:
313     temp = GaussianRandomNumber();
314     break;
315   default:
316     cerr << "Unknown function operation type" << endl;
317     break;
318   }
319
320   return temp;
321 }
322
323 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324
325 string FGFunction::GetValueAsString(void) const
326 {
327   ostringstream buffer;
328
329   buffer << setw(9) << setprecision(6) << GetValue();
330   return buffer.str();
331 }
332
333 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334
335 void FGFunction::bind(void)
336 {
337   if ( !Name.empty() ) {
338     string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
339     PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
340   }
341 }
342
343 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344 //    The bitmasked value choices are as follows:
345 //    unset: In this case (the default) JSBSim would only print
346 //       out the normally expected messages, essentially echoing
347 //       the config files as they are read. If the environment
348 //       variable is not set, debug_lvl is set to 1 internally
349 //    0: This requests JSBSim not to output any messages
350 //       whatsoever.
351 //    1: This value explicity requests the normal JSBSim
352 //       startup messages
353 //    2: This value asks for a message to be printed out when
354 //       a class is instantiated
355 //    4: When this value is set, a message is displayed when a
356 //       FGModel object executes its Run() method
357 //    8: When this value is set, various runtime state variables
358 //       are printed out periodically
359 //    16: When set various parameters are sanity checked and
360 //       a message is printed out when they go out of bounds
361
362 void FGFunction::Debug(int from)
363 {
364   if (debug_lvl <= 0) return;
365
366   if (debug_lvl & 1) { // Standard console startup message output
367     if (from == 0) { // Constructor
368       if (Type == eTopLevel)
369         cout << "    Function: " << Name << endl;
370     }
371   }
372   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
373     if (from == 0) cout << "Instantiated: FGFunction" << endl;
374     if (from == 1) cout << "Destroyed:    FGFunction" << endl;
375   }
376   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
377   }
378   if (debug_lvl & 8 ) { // Runtime state variables
379   }
380   if (debug_lvl & 16) { // Sanity checking
381   }
382   if (debug_lvl & 64) {
383     if (from == 0) { // Constructor
384       cout << IdSrc << endl;
385       cout << IdHdr << endl;
386     }
387   }
388 }
389
390 }