]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/math/FGFunction.cpp
Sync w. JSBSim CVS (merge from PRE_OSG_PLIB_20061029 branch)
[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 (jsb@hal-pc.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   Name = el->GetAttributeValue("name");
57   operation = el->GetName();
58
59   if (operation == string("function")) {
60     Type = eTopLevel;
61   } else if (operation == string("product")) {
62     Type = eProduct;
63   } else if (operation == string("difference")) {
64     Type = eDifference;
65   } else if (operation == string("sum")) {
66     Type = eSum;
67   } else if (operation == string("quotient")) {
68     Type = eQuotient;
69   } else if (operation == string("pow")) {
70     Type = ePow;
71   } else if (operation == string("abs")) {
72     Type = eAbs;
73   } else if (operation == string("sin")) {
74     Type = eSin;
75   } else if (operation == string("exp")) {
76     Type = eExp;
77   } else if (operation == string("cos")) {
78     Type = eCos;
79   } else if (operation == string("tan")) {
80     Type = eTan;
81   } else if (operation == string("asin")) {
82     Type = eASin;
83   } else if (operation == string("acos")) {
84     Type = eACos;
85   } else if (operation == string("atan")) {
86     Type = eATan;
87   } else if (operation == string("atan2")) {
88     Type = eATan2;
89   } else if (operation != string("description")) {
90     cerr << "Bad operation " << operation << " detected in configuration file" << endl;
91   }
92
93   element = el->GetElement();
94   if (!element) {
95     cerr << fgred << highint << endl;
96     cerr << "  No element was specified as an argument to the \"" << operation << "\" operation" << endl;
97     cerr << "  This can happen when, for instance, a cos operation is specified and a " << endl;
98     cerr << "  property name is given explicitly, but is not placed within a" << endl;
99     cerr << "  <property></property> element tag pair." << endl;
100     cerr << reset;
101     exit(-2);
102   }
103   
104   while (element) {
105     operation = element->GetName();
106
107     // data types
108     if (operation == string("property")) {
109       property_name = element->GetDataLine();
110       FGPropertyManager* newNode = PropertyManager->GetNode(property_name);
111       if (newNode == 0) {
112         cerr << "The property " << property_name << " is undefined." << endl;
113         abort();
114       } else {
115         Parameters.push_back(new FGPropertyValue( newNode ));
116       }
117     } else if (operation == string("value")) {
118       Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
119     } else if (operation == string("table")) {
120       Parameters.push_back(new FGTable(PropertyManager, element));
121     // operations
122     } else if (operation == string("product") ||
123                operation == string("difference") ||
124                operation == string("sum") ||
125                operation == string("quotient") ||
126                operation == string("pow") ||
127                operation == string("exp") ||
128                operation == string("abs") ||
129                operation == string("sin") ||
130                operation == string("cos") ||
131                operation == string("tan") ||
132                operation == string("asin") ||
133                operation == string("acos") ||
134                operation == string("atan") ||
135                operation == string("atan2"))
136     {
137       Parameters.push_back(new FGFunction(PropertyManager, element));
138     } else if (operation != string("description")) {
139       cerr << "Bad operation " << operation << " detected in configuration file" << endl;
140     }
141     element = el->GetNextElement();
142   }
143
144   bind(); // Allow any function to save its value
145
146   Debug(0);
147 }
148
149 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
150
151 FGFunction::~FGFunction(void)
152 {
153   if (!Name.empty()) {
154     string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
155     PropertyManager->Untie(tmp);
156   }
157
158   for (unsigned int i=0; i<Parameters.size(); i++) {
159     delete Parameters[i];
160   }
161 }
162
163 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
164
165 void FGFunction::cacheValue(bool cache)
166 {
167   cached = false; // Must set cached to false prior to calling GetValue(), else
168                   // it will _never_ calculate the value;
169   if (cache) {
170     cachedValue = GetValue();
171     cached = true;
172   }
173 }
174
175 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
176
177 double FGFunction::GetValue(void) const
178 {
179   unsigned int i;
180
181   if (cached) return cachedValue;
182
183   double temp = Parameters[0]->GetValue();
184
185   switch (Type) {
186   case eTopLevel:
187     break;
188   case eProduct:
189     for (i=1;i<Parameters.size();i++) {
190       temp *= Parameters[i]->GetValue();
191     }
192     break;
193   case eDifference:
194     for (i=1;i<Parameters.size();i++) {
195       temp -= Parameters[i]->GetValue();
196     }
197     break;
198   case eSum:
199     for (i=1;i<Parameters.size();i++) {
200       temp += Parameters[i]->GetValue();
201     }
202     break;
203   case eQuotient:
204     temp /= Parameters[1]->GetValue();
205     break;
206   case ePow:
207     temp = pow(temp,Parameters[1]->GetValue());
208     break;
209   case eExp:
210     temp = exp(temp);
211     break;
212   case eAbs:
213     temp = fabs(temp);
214     break;
215   case eSin:
216     temp = sin(temp);
217     break;
218   case eCos:
219     temp = cos(temp);
220     break;
221   case eTan:
222     temp = tan(temp);
223     break;
224   case eACos:
225     temp = acos(temp);
226     break;
227   case eASin:
228     temp = asin(temp);
229     break;
230   case eATan:
231     temp = atan(temp);
232     break;
233   case eATan2:
234     temp = atan2(temp, Parameters[1]->GetValue());
235     break;
236   default:
237     cerr << "Unknown function operation type" << endl;
238     break;
239   }
240
241   return temp;
242 }
243
244 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
245
246 string FGFunction::GetValueAsString(void) const
247 {
248   char buffer[20];
249   string value;
250
251   sprintf(buffer,"%9.6f",GetValue());
252   value = string(buffer);
253   return value;
254 }
255
256 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
257
258 void FGFunction::bind(void)
259 {
260   if ( !Name.empty() ) {
261     string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
262     PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
263   }
264 }
265
266 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267 //    The bitmasked value choices are as follows:
268 //    unset: In this case (the default) JSBSim would only print
269 //       out the normally expected messages, essentially echoing
270 //       the config files as they are read. If the environment
271 //       variable is not set, debug_lvl is set to 1 internally
272 //    0: This requests JSBSim not to output any messages
273 //       whatsoever.
274 //    1: This value explicity requests the normal JSBSim
275 //       startup messages
276 //    2: This value asks for a message to be printed out when
277 //       a class is instantiated
278 //    4: When this value is set, a message is displayed when a
279 //       FGModel object executes its Run() method
280 //    8: When this value is set, various runtime state variables
281 //       are printed out periodically
282 //    16: When set various parameters are sanity checked and
283 //       a message is printed out when they go out of bounds
284
285 void FGFunction::Debug(int from)
286 {
287   if (debug_lvl <= 0) return;
288
289   if (debug_lvl & 1) { // Standard console startup message output
290     if (from == 0) { // Constructor
291       if (Type == eTopLevel)
292         cout << "    Function: " << Name << endl;
293     }
294   }
295   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
296     if (from == 0) cout << "Instantiated: FGFunction" << endl;
297     if (from == 1) cout << "Destroyed:    FGFunction" << endl;
298   }
299   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
300   }
301   if (debug_lvl & 8 ) { // Runtime state variables
302   }
303   if (debug_lvl & 16) { // Sanity checking
304   }
305   if (debug_lvl & 64) {
306     if (from == 0) { // Constructor
307       cout << IdSrc << endl;
308       cout << IdHdr << endl;
309     }
310   }
311 }
312
313 }