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