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