]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/math/FGFunction.cpp
Sync with JSBSim CVS again
[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 <stdio.h>
32
33 #include "FGFunction.h"
34 #include "FGTable.h"
35 #include "FGPropertyValue.h"
36 #include "FGRealValue.h"
37
38 namespace JSBSim {
39
40 static const char *IdSrc = "$Id$";
41 static const char *IdHdr = ID_FUNCTION;
42
43 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
44 CLASS IMPLEMENTATION
45 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
46
47 FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
48                                       : PropertyManager(propMan), Prefix(prefix)
49 {
50   Element* element;
51   string operation, property_name;
52   int size = el->GetNumElements();
53   cached = false;
54   cachedValue = -HUGE_VAL;
55
56   property_string = "property";
57   value_string = "value";
58   table_string = "table";
59   p_string = "p";
60   v_string = "v";
61   t_string = "t";
62
63   function_string = "function";
64   description_string = "description";
65   sum_string = "sum";
66   difference_string = "difference";
67   product_string = "product";
68   quotient_string = "quotient";
69   pow_string = "pow";
70   exp_string = "exp";
71   abs_string = "abs";
72   sin_string = "sin";
73   cos_string = "cos";
74   tan_string = "tan";
75   asin_string = "asin";
76   acos_string = "acos";
77   atan_string = "atan";
78   atan2_string = "atan2";
79   min_string = "min";
80   max_string = "max";
81   avg_string = "avg";
82   fraction_string = "fraction";
83   mod_string = "mod";
84   random_string = "random";
85   integer_string = "integer";
86
87   Name = el->GetAttributeValue("name");
88   operation = el->GetName();
89
90   if (operation == function_string) {
91     Type = eTopLevel;
92   } else if (operation == product_string) {
93     Type = eProduct;
94   } else if (operation == difference_string) {
95     Type = eDifference;
96   } else if (operation == sum_string) {
97     Type = eSum;
98   } else if (operation == quotient_string) {
99     Type = eQuotient;
100   } else if (operation == pow_string) {
101     Type = ePow;
102   } else if (operation == abs_string) {
103     Type = eAbs;
104   } else if (operation == sin_string) {
105     Type = eSin;
106   } else if (operation == exp_string) {
107     Type = eExp;
108   } else if (operation == cos_string) {
109     Type = eCos;
110   } else if (operation == tan_string) {
111     Type = eTan;
112   } else if (operation == asin_string) {
113     Type = eASin;
114   } else if (operation == acos_string) {
115     Type = eACos;
116   } else if (operation == atan_string) {
117     Type = eATan;
118   } else if (operation == atan2_string) {
119     Type = eATan2;
120   } else if (operation == min_string) {
121     Type = eMin;
122   } else if (operation == max_string) {
123     Type = eMax;
124   } else if (operation == avg_string) {
125     Type = eAvg;
126   } else if (operation == fraction_string) {
127     Type = eFrac;
128   } else if (operation == integer_string) {
129     Type = eInteger;
130   } else if (operation == mod_string) {
131     Type = eMod;
132   } else if (operation == random_string) {
133     Type = eRandom;
134   } else if (operation != description_string) {
135     cerr << "Bad operation " << operation << " detected in configuration file" << endl;
136   }
137
138   element = el->GetElement();
139   if (!element) {
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;
145     cerr << reset;
146     exit(-2);
147   }
148   
149   while (element) {
150     operation = element->GetName();
151
152     // data types
153     if (operation == property_string || operation == p_string) {
154       property_name = element->GetDataLine();
155       FGPropertyManager* newNode = PropertyManager->GetNode(property_name);
156       if (newNode == 0) {
157         cerr << "The property " << property_name << " is undefined." << endl;
158         abort();
159       } else {
160         Parameters.push_back(new FGPropertyValue( newNode ));
161       }
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));
166     // operations
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 )
188     {
189       Parameters.push_back(new FGFunction(PropertyManager, element));
190     } else if (operation != description_string) {
191       cerr << "Bad operation " << operation << " detected in configuration file" << endl;
192     }
193     element = el->GetNextElement();
194   }
195
196   bind(); // Allow any function to save its value
197
198   Debug(0);
199 }
200
201 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
202
203 FGFunction::~FGFunction(void)
204 {
205   for (unsigned int i=0; i<Parameters.size(); i++) delete Parameters[i];
206 }
207
208 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
209
210 void FGFunction::cacheValue(bool cache)
211 {
212   cached = false; // Must set cached to false prior to calling GetValue(), else
213                   // it will _never_ calculate the value;
214   if (cache) {
215     cachedValue = GetValue();
216     cached = true;
217   }
218 }
219
220 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
221
222 double FGFunction::GetValue(void) const
223 {
224   unsigned int i;
225   double scratch;
226
227   if (cached) return cachedValue;
228
229   double temp = Parameters[0]->GetValue();
230
231   switch (Type) {
232   case eTopLevel:
233     break;
234   case eProduct:
235     for (i=1;i<Parameters.size();i++) {
236       temp *= Parameters[i]->GetValue();
237     }
238     break;
239   case eDifference:
240     for (i=1;i<Parameters.size();i++) {
241       temp -= Parameters[i]->GetValue();
242     }
243     break;
244   case eSum:
245     for (i=1;i<Parameters.size();i++) {
246       temp += Parameters[i]->GetValue();
247     }
248     break;
249   case eQuotient:
250     temp /= Parameters[1]->GetValue();
251     break;
252   case ePow:
253     temp = pow(temp,Parameters[1]->GetValue());
254     break;
255   case eExp:
256     temp = exp(temp);
257     break;
258   case eAbs:
259     temp = fabs(temp);
260     break;
261   case eSin:
262     temp = sin(temp);
263     break;
264   case eCos:
265     temp = cos(temp);
266     break;
267   case eTan:
268     temp = tan(temp);
269     break;
270   case eACos:
271     temp = acos(temp);
272     break;
273   case eASin:
274     temp = asin(temp);
275     break;
276   case eATan:
277     temp = atan(temp);
278     break;
279   case eATan2:
280     temp = atan2(temp, Parameters[1]->GetValue());
281     break;
282   case eMod:
283     temp = ((int)temp) % ((int) Parameters[1]->GetValue());
284     break;
285   case eMin:
286     for (i=1;i<Parameters.size();i++) {
287       if (Parameters[i]->GetValue() < temp) temp = Parameters[i]->GetValue();
288     }    
289     break;
290   case eMax:
291     for (i=1;i<Parameters.size();i++) {
292       if (Parameters[i]->GetValue() > temp) temp = Parameters[i]->GetValue();
293     }    
294     break;
295   case eAvg:
296     for (i=1;i<Parameters.size();i++) {
297       temp += Parameters[i]->GetValue();
298     }
299     temp /= Parameters.size();
300     break;
301   case eFrac:
302     temp = modf(temp, &scratch);
303     break;
304   case eInteger:
305     modf(temp, &scratch);
306     temp = scratch;
307     break;
308   case eRandom:
309     temp = GaussianRandomNumber();
310     break;
311   default:
312     cerr << "Unknown function operation type" << endl;
313     break;
314   }
315
316   return temp;
317 }
318
319 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320
321 string FGFunction::GetValueAsString(void) const
322 {
323   char buffer[20];
324   string value;
325
326   sprintf(buffer,"%9.6f",GetValue());
327   value = string(buffer);
328   return value;
329 }
330
331 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
332
333 void FGFunction::bind(void)
334 {
335   if ( !Name.empty() ) {
336     string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
337     PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
338   }
339 }
340
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
348 //       whatsoever.
349 //    1: This value explicity requests the normal JSBSim
350 //       startup messages
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
359
360 void FGFunction::Debug(int from)
361 {
362   if (debug_lvl <= 0) return;
363
364   if (debug_lvl & 1) { // Standard console startup message output
365     if (from == 0) { // Constructor
366       if (Type == eTopLevel)
367         cout << "    Function: " << Name << endl;
368     }
369   }
370   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
371     if (from == 0) cout << "Instantiated: FGFunction" << endl;
372     if (from == 1) cout << "Destroyed:    FGFunction" << endl;
373   }
374   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
375   }
376   if (debug_lvl & 8 ) { // Runtime state variables
377   }
378   if (debug_lvl & 16) { // Sanity checking
379   }
380   if (debug_lvl & 64) {
381     if (from == 0) { // Constructor
382       cout << IdSrc << endl;
383       cout << IdHdr << endl;
384     }
385   }
386 }
387
388 }