]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/math/FGTable.cpp
Remove a bunch of unneede files.
[flightgear.git] / src / FDM / JSBSim / math / FGTable.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGTable.cpp
4  Author:       Jon S. Berndt
5  Date started: 1/9/2001
6  Purpose:      Models a lookup table
7
8  ------------- Copyright (C) 2001  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 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 General Public License for more
18  details.
19
20  You should have received a copy of the GNU 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 General Public License can also be found on
25  the world wide web at http://www.gnu.org.
26
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
29 Models a lookup table
30
31 HISTORY
32 --------------------------------------------------------------------------------
33 JSB  1/9/00          Created
34
35 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36 INCLUDES
37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38
39 #include "FGTable.h"
40
41 #if defined ( sgi ) && !defined( __GNUC__ ) && (_COMPILER_VERSION < 740)
42 # include <iomanip.h>
43 #else
44 # include <iomanip>
45 #endif
46
47 using namespace std;
48
49 namespace JSBSim {
50
51 static const char *IdSrc = "$Id$";
52 static const char *IdHdr = ID_TABLE;
53
54 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55 CLASS IMPLEMENTATION
56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
57
58 FGTable::FGTable(int NRows) : nRows(NRows), nCols(1), PropertyManager(0)
59 {
60   Type = tt1D;
61   colCounter = 0;
62   rowCounter = 1;
63   nTables = 0;
64
65   Data = Allocate();
66   Debug(0);
67   lastRowIndex=lastColumnIndex=2;
68 }
69
70 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71
72 FGTable::FGTable(const FGTable& t) : PropertyManager(t.PropertyManager)
73 {
74   Type = t.Type;
75   colCounter = t.colCounter;
76   rowCounter = t.rowCounter;
77   tableCounter = t.tableCounter;
78   nRows = t.nRows;
79   nCols = t.nCols;
80   nTables = t.nTables;
81   dimension = t.dimension;
82   internal = t.internal;
83
84   Tables = t.Tables;
85   Data = Allocate();
86   for (int r=0; r<=nRows; r++) {
87     for (int c=0; c<=nCols; c++) {
88       Data[r][c] = t.Data[r][c];
89     }
90   }
91   lastRowIndex = t.lastRowIndex;
92   lastColumnIndex = t.lastColumnIndex;
93   lastTableIndex = t.lastTableIndex;
94 }
95
96 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
97
98 FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(propMan)
99 {
100   int i;
101
102   stringstream buf;
103   string property_string;
104   string lookup_axis;
105   string call_type;
106   string parent_type;
107   FGPropertyManager* node;
108   Element *tableData;
109   Element *parent_element;
110   Element *axisElement;
111   string operation_types = "function, product, sum, difference, quotient,"
112                            "pow, abs, sin, cos, asin, acos, tan, atan, table";
113
114   nTables = 0;
115
116   // Is this an internal lookup table?
117
118   internal = false;
119   call_type = el->GetAttributeValue("type");
120   if (call_type == string("internal")) {
121     parent_element = el->GetParent();
122     parent_type = parent_element->GetName();
123     if (operation_types.find(parent_type) == string::npos) {
124       internal = true;
125     } else {
126       // internal table is a child element of a restricted type
127       cerr << endl << fgred << "  An internal table cannot be nested within another type," << endl;
128       cerr << "  such as a function. The 'internal' keyword is ignored." << fgdef << endl << endl;
129     }
130   } else if (!call_type.empty()) {
131     cerr << endl << fgred << "  An unknown table type attribute is listed: " << call_type
132                  << ". Execution cannot continue." << fgdef << endl << endl;
133     abort();
134   }
135
136   // Determine and store the lookup properties for this table unless this table
137   // is part of a 3D table, in which case its independentVar property indexes will
138   // be set by a call from the owning table during creation
139
140   dimension = 0;
141
142   axisElement = el->FindElement("independentVar");
143   if (axisElement) {
144
145     // The 'internal' attribute of the table element cannot be specified
146     // at the same time that independentVars are specified.
147     if (internal) {
148       cerr << endl << fgred << "  This table specifies both 'internal' call type" << endl;
149       cerr << "  and specific lookup properties via the 'independentVar' element." << endl;
150       cerr << "  These are mutually exclusive specifications. The 'internal'" << endl;
151       cerr << "  attribute will be ignored." << fgdef << endl << endl;
152       internal = false;
153     }
154
155     for (i=0; i<3; i++) lookupProperty[i] = 0;
156
157     while (axisElement) {
158       property_string = axisElement->GetDataLine();
159       node = PropertyManager->GetNode(property_string);
160
161       lookup_axis = axisElement->GetAttributeValue("lookup");
162       if (lookup_axis == string("row")) {
163         lookupProperty[eRow] = node;
164       } else if (lookup_axis == string("column")) {
165         lookupProperty[eColumn] = node;
166       } else if (lookup_axis == string("table")) {
167         lookupProperty[eTable] = node;
168       } else { // assumed single dimension table; row lookup
169         lookupProperty[eRow] = node;
170       }
171       dimension++;
172       axisElement = el->FindNextElement("independentVar");
173     }
174
175   } else if (internal) { // This table is an internal table
176
177   // determine how many rows, columns, and tables in this table (dimension).
178
179     if (el->GetNumElements("tableData") > 1) {
180       dimension = 3; // this is a 3D table
181     } else {
182       tableData = el->FindElement("tableData");
183       string test_line = tableData->GetDataLine(1);  // examine second line in table for dimension
184       if (FindNumColumns(test_line) == 2) dimension = 1;    // 1D table
185       else if (FindNumColumns(test_line) > 2) dimension = 2; // 2D table
186       else {
187         cerr << "Invalid number of columns in table" << endl;
188       }
189     }
190
191   } else { // no independentVars found, and table is not marked as internal
192     cerr << endl << fgred << "No independent variable found for table." << fgdef << endl << endl;
193     abort();
194   }
195   // end lookup property code
196
197   tableData = el->FindElement("tableData");
198   for (i=0; i<tableData->GetNumDataLines(); i++) {
199     buf << tableData->GetDataLine(i) << string(" ");
200   }
201   switch (dimension) {
202   case 1:
203     nRows = tableData->GetNumDataLines();
204     nCols = 1;
205     Type = tt1D;
206     colCounter = 0;
207     rowCounter = 1;
208     Data = Allocate();
209     Debug(0);
210     lastRowIndex = lastColumnIndex = 2;
211     *this << buf;
212     break;
213   case 2:
214     nRows = tableData->GetNumDataLines()-1;
215
216     if (nRows >= 2) nCols = FindNumColumns(tableData->GetDataLine(0));
217     else {
218       cerr << endl << fgred << "Not enough rows in this table." << fgdef << endl;
219       abort();
220     }
221
222     Type = tt2D;
223     colCounter = 1;
224     rowCounter = 0;
225
226     Data = Allocate();
227     lastRowIndex = lastColumnIndex = 2;
228     *this << buf;
229     break;
230   case 3:
231     nTables = el->GetNumElements("tableData");
232     nRows = nTables;
233     nCols = 1;
234     Type = tt3D;
235     colCounter = 1;
236     rowCounter = 1;
237
238     Data = Allocate(); // this data array will contain the keys for the associated tables
239     Tables.reserve(nTables); // necessary?
240     tableData = el->FindElement("tableData");
241     for (i=0; i<nTables; i++) {
242       Tables.push_back(new FGTable(PropertyManager, tableData));
243       Data[i+1][1] = tableData->GetAttributeValueAsNumber("breakPoint");
244       Tables[i]->SetRowIndexProperty(lookupProperty[eRow]);
245       Tables[i]->SetColumnIndexProperty(lookupProperty[eColumn]);
246       tableData = el->FindNextElement("tableData");
247     }
248
249     Debug(0);
250     break;
251   default:
252     cout << "No dimension given" << endl;
253     break;
254   }
255   if (debug_lvl & 1) Print();
256 }
257
258 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259
260 double** FGTable::Allocate(void)
261 {
262   Data = new double*[nRows+1];
263   for (int r=0; r<=nRows; r++) {
264     Data[r] = new double[nCols+1];
265     for (int c=0; c<=nCols; c++) {
266       Data[r][c] = 0.0;
267     }
268   }
269   return Data;
270 }
271
272 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
273
274 FGTable::~FGTable()
275 {
276   if (nTables > 0) {
277 cout << "nTables = " << nTables << endl;
278     for (int i=0; i<nTables; i++) delete Tables[i];
279     Tables.clear();
280   }
281   for (int r=0; r<=nRows; r++) if (Data[r]) delete[] Data[r];
282   if (Data) delete[] Data;
283   Debug(1);
284 }
285
286 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287
288 int FGTable::FindNumColumns(string test_line)
289 {
290   // determine number of data columns in table (first column is row lookup - don't count)
291   int position=0;
292   int nCols=0;
293   while ((position = test_line.find_first_not_of(" \t", position)) != string::npos) {
294     nCols++;
295     position = test_line.find_first_of(" \t", position);
296   }
297   return nCols;
298 }
299
300 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301
302 double FGTable::GetValue(void) const
303 {
304   double temp = 0;
305   double temp2 = 0;
306
307   switch (Type) {
308   case tt1D:
309     temp = lookupProperty[eRow]->getDoubleValue();
310     temp2 = GetValue(temp);
311     return temp2;
312   case tt2D:
313     return GetValue(lookupProperty[eRow]->getDoubleValue(),
314                     lookupProperty[eColumn]->getDoubleValue());
315   case tt3D:
316     return GetValue(lookupProperty[eRow]->getDoubleValue(),
317                     lookupProperty[eColumn]->getDoubleValue(),
318                     lookupProperty[eTable]->getDoubleValue());
319   default:
320     cerr << "Attempted to GetValue() for invalid/unknown table type" << endl;
321     throw(string("Attempted to GetValue() for invalid/unknown table type"));
322   }
323 }
324
325 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326
327 double FGTable::GetValue(double key) const
328 {
329   double Factor, Value, Span;
330   int r=lastRowIndex;
331
332   //if the key is off the end of the table, just return the
333   //end-of-table value, do not extrapolate
334   if( key <= Data[1][0] ) {
335     lastRowIndex=2;
336     //cout << "Key underneath table: " << key << endl;
337     return Data[1][1];
338   } else if ( key >= Data[nRows][0] ) {
339     lastRowIndex=nRows;
340     //cout << "Key over table: " << key << endl;
341     return Data[nRows][1];
342   }
343
344   // the key is somewhere in the middle, search for the right breakpoint
345   // assume the correct breakpoint has not changed since last frame or
346   // has only changed very little
347
348   if ( r > 2 && Data[r-1][0] > key ) {
349     while( Data[r-1][0] > key && r > 2) { r--; }
350   } else if ( Data[r][0] < key ) {
351     while( Data[r][0] <= key && r <= nRows) { r++; }
352   }
353
354   lastRowIndex=r;
355   // make sure denominator below does not go to zero.
356
357   Span = Data[r][0] - Data[r-1][0];
358   if (Span != 0.0) {
359     Factor = (key - Data[r-1][0]) / Span;
360     if (Factor > 1.0) Factor = 1.0;
361   } else {
362     Factor = 1.0;
363   }
364
365   Value = Factor*(Data[r][1] - Data[r-1][1]) + Data[r-1][1];
366
367   return Value;
368 }
369
370 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371
372 double FGTable::GetValue(double rowKey, double colKey) const
373 {
374   double rFactor, cFactor, col1temp, col2temp, Value;
375   int r=lastRowIndex;
376   int c=lastColumnIndex;
377
378   if ( r > 2 && Data[r-1][0] > rowKey ) {
379     while ( Data[r-1][0] > rowKey && r > 2) { r--; }
380   } else if ( Data[r][0] < rowKey ) {
381     while ( r <= nRows && Data[r][0] <= rowKey ) { r++; }
382     if ( r > nRows ) r = nRows;
383   }
384
385   if ( c > 2 && Data[0][c-1] > colKey ) {
386     while( Data[0][c-1] > colKey && c > 2) { c--; }
387   } else if ( Data[0][c] < colKey ) {
388     while( Data[0][c] <= colKey && c <= nCols) { c++; }
389     if ( c > nCols ) c = nCols;
390   }
391
392   lastRowIndex=r;
393   lastColumnIndex=c;
394
395   rFactor = (rowKey - Data[r-1][0]) / (Data[r][0] - Data[r-1][0]);
396   cFactor = (colKey - Data[0][c-1]) / (Data[0][c] - Data[0][c-1]);
397
398   if (rFactor > 1.0) rFactor = 1.0;
399   else if (rFactor < 0.0) rFactor = 0.0;
400
401   if (cFactor > 1.0) cFactor = 1.0;
402   else if (cFactor < 0.0) cFactor = 0.0;
403
404   col1temp = rFactor*(Data[r][c-1] - Data[r-1][c-1]) + Data[r-1][c-1];
405   col2temp = rFactor*(Data[r][c] - Data[r-1][c]) + Data[r-1][c];
406
407   Value = col1temp + cFactor*(col2temp - col1temp);
408
409   return Value;
410 }
411
412 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
413
414 double FGTable::GetValue(double rowKey, double colKey, double tableKey) const
415 {
416   double Factor, Value, Span;
417   int r=lastRowIndex;
418
419   //if the key is off the end  (or before the beginning) of the table,
420   // just return the boundary-table value, do not extrapolate
421
422   if( tableKey <= Data[1][1] ) {
423     lastRowIndex=2;
424     return Tables[0]->GetValue(rowKey, colKey);
425   } else if ( tableKey >= Data[nRows][1] ) {
426     lastRowIndex=nRows;
427     return Tables[nRows-1]->GetValue(rowKey, colKey);
428   }
429
430   // the key is somewhere in the middle, search for the right breakpoint
431   // assume the correct breakpoint has not changed since last frame or
432   // has only changed very little
433
434   if ( r > 2 && Data[r-1][1] > tableKey ) {
435     while( Data[r-1][1] > tableKey && r > 2) { r--; }
436   } else if ( Data[r][1] < tableKey ) {
437     while( Data[r][1] <= tableKey && r <= nRows) { r++; }
438   }
439
440   lastRowIndex=r;
441   // make sure denominator below does not go to zero.
442
443   Span = Data[r][1] - Data[r-1][1];
444   if (Span != 0.0) {
445     Factor = (tableKey - Data[r-1][1]) / Span;
446     if (Factor > 1.0) Factor = 1.0;
447   } else {
448     Factor = 1.0;
449   }
450
451   Value = Factor*(Tables[r-1]->GetValue(rowKey, colKey) - Tables[r-2]->GetValue(rowKey, colKey))
452                               + Tables[r-2]->GetValue(rowKey, colKey);
453
454   return Value;
455 }
456
457 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458
459 void FGTable::operator<<(stringstream& in_stream)
460 {
461   int startRow=0;
462   int startCol=0;
463
464   if (Type == tt1D || Type == tt3D) startRow = 1;
465   if (Type == tt3D) startCol = 1;
466
467   for (int r=startRow; r<=nRows; r++) {
468     for (int c=startCol; c<=nCols; c++) {
469       if (r != 0 || c != 0) {
470         in_stream >> Data[r][c];
471       }
472     }
473   }
474 }
475
476 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477
478 FGTable& FGTable::operator<<(const double n)
479 {
480   Data[rowCounter][colCounter] = n;
481   if (colCounter == nCols) {
482     colCounter = 0;
483     rowCounter++;
484   } else {
485     colCounter++;
486   }
487   return *this;
488 }
489
490 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
491
492 FGTable& FGTable::operator<<(const int n)
493 {
494   *this << (double)n;
495   return *this;
496 }
497
498 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499
500 void FGTable::Print(void)
501 {
502   int startRow=0;
503   int startCol=0;
504
505   if (Type == tt1D || Type == tt3D) startRow = 1;
506   if (Type == tt3D) startCol = 1;
507
508 #if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
509   unsigned long flags = cout.setf(ios::fixed);
510 #else
511   ios::fmtflags flags = cout.setf(ios::fixed); // set up output stream
512 #endif
513
514   switch(Type) {
515     case tt1D:
516       cout << "    1 dimensional table with " << nRows << " rows." << endl;
517       break;
518     case tt2D:
519       cout << "    2 dimensional table with " << nRows << " rows, " << nCols << " columns." << endl;
520       break;
521     case tt3D:
522       cout << "    3 dimensional table with " << nRows << " rows, "
523                                           << nCols << " columns "
524                                           << nTables << " tables." << endl;
525       break;
526   }
527   cout.precision(4);
528   for (int r=startRow; r<=nRows; r++) {
529     cout << "   ";
530     for (int c=startCol; c<=nCols; c++) {
531       if (r == 0 && c == 0) {
532         cout << "       ";
533       } else {
534         cout << Data[r][c] << " ";
535         if (Type == tt3D) {
536           cout << endl;
537           Tables[r-1]->Print();
538         }
539       }
540     }
541     cout << endl;
542   }
543   cout.setf(flags); // reset
544 }
545
546 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547 //    The bitmasked value choices are as follows:
548 //    unset: In this case (the default) JSBSim would only print
549 //       out the normally expected messages, essentially echoing
550 //       the config files as they are read. If the environment
551 //       variable is not set, debug_lvl is set to 1 internally
552 //    0: This requests JSBSim not to output any messages
553 //       whatsoever.
554 //    1: This value explicity requests the normal JSBSim
555 //       startup messages
556 //    2: This value asks for a message to be printed out when
557 //       a class is instantiated
558 //    4: When this value is set, a message is displayed when a
559 //       FGModel object executes its Run() method
560 //    8: When this value is set, various runtime state variables
561 //       are printed out periodically
562 //    16: When set various parameters are sanity checked and
563 //       a message is printed out when they go out of bounds
564
565 void FGTable::Debug(int from)
566 {
567   if (debug_lvl <= 0) return;
568
569   if (debug_lvl & 1) { // Standard console startup message output
570     if (from == 0) { // Constructor
571
572     }
573   }
574   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
575     if (from == 0) cout << "Instantiated: FGTable" << endl;
576     if (from == 1) cout << "Destroyed:    FGTable" << endl;
577   }
578   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
579   }
580   if (debug_lvl & 8 ) { // Runtime state variables
581   }
582   if (debug_lvl & 16) { // Sanity checking
583   }
584   if (debug_lvl & 64) {
585     if (from == 0) { // Constructor
586       cout << IdSrc << endl;
587       cout << IdHdr << endl;
588     }
589   }
590 }
591 }