JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
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 IDENT(IdSrc,"$Id: FGTable.cpp,v 1.32 2016/05/22 09:08:05 bcoconni Exp $");
51 IDENT(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  FGPropertyNode* 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  cerr << axisElement->ReadFrom();
182  throw("IndependentVar property, " + property_string + " in Table definition is not defined.");
183  }
184 
185  lookup_axis = axisElement->GetAttributeValue("lookup");
186  if (lookup_axis == string("row")) {
187  lookupProperty[eRow] = node;
188  } else if (lookup_axis == string("column")) {
189  lookupProperty[eColumn] = node;
190  } else if (lookup_axis == string("table")) {
191  lookupProperty[eTable] = node;
192  } else if (!lookup_axis.empty()) {
193  throw("Lookup table axis specification not understood: " + lookup_axis);
194  } else { // assumed single dimension table; row lookup
195  lookupProperty[eRow] = node;
196  }
197  dimension++;
198  axisElement = el->FindNextElement("independentVar");
199  }
200 
201  } else if (internal) { // This table is an internal table
202 
203  // determine how many rows, columns, and tables in this table (dimension).
204 
205  if (el->GetNumElements("tableData") > 1) {
206  dimension = 3; // this is a 3D table
207  } else {
208  tableData = el->FindElement("tableData");
209  string test_line = tableData->GetDataLine(1); // examine second line in table for dimension
210  if (FindNumColumns(test_line) == 2) dimension = 1; // 1D table
211  else if (FindNumColumns(test_line) > 2) dimension = 2; // 2D table
212  else {
213  cerr << "Invalid number of columns in table" << endl;
214  }
215  }
216 
217  } else {
218  brkpt_string = el->GetAttributeValue("breakPoint");
219  if (brkpt_string.empty()) {
220  // no independentVars found, and table is not marked as internal, nor is it a 3D table
221  throw("No independent variable found for table.");
222  }
223  }
224  // end lookup property code
225 
226  if (brkpt_string.empty()) { // Not a 3D table "table element"
227  tableData = el->FindElement("tableData");
228  } else { // This is a table in a 3D table
229  tableData = el;
230  dimension = 2; // Currently, infers 2D table
231  }
232 
233  for (i=0; i<tableData->GetNumDataLines(); i++) {
234  buf << tableData->GetDataLine(i) << string(" ");
235  }
236  switch (dimension) {
237  case 1:
238  nRows = tableData->GetNumDataLines();
239  nCols = 1;
240  Type = tt1D;
241  colCounter = 0;
242  rowCounter = 1;
243  Data = Allocate();
244  Debug(0);
245  lastRowIndex = lastColumnIndex = 2;
246  *this << buf;
247  break;
248  case 2:
249  nRows = tableData->GetNumDataLines()-1;
250 
251  if (nRows >= 2) {
252  nCols = FindNumColumns(tableData->GetDataLine(0));
253  if (nCols < 2) throw(string("Not enough columns in table data."));
254  } else {
255  throw(string("Not enough rows in the table data."));
256  }
257 
258  Type = tt2D;
259  colCounter = 1;
260  rowCounter = 0;
261 
262  Data = Allocate();
263  lastRowIndex = lastColumnIndex = 2;
264  *this << buf;
265  break;
266  case 3:
267  nTables = el->GetNumElements("tableData");
268  nRows = nTables;
269  nCols = 1;
270  Type = tt3D;
271  colCounter = 1;
272  rowCounter = 1;
273  lastRowIndex = lastColumnIndex = 2;
274 
275  Data = Allocate(); // this data array will contain the keys for the associated tables
276  Tables.reserve(nTables); // necessary?
277  tableData = el->FindElement("tableData");
278  for (i=0; i<nTables; i++) {
279  Tables.push_back(new FGTable(PropertyManager, tableData));
280  Data[i+1][1] = tableData->GetAttributeValueAsNumber("breakPoint");
281  Tables[i]->SetRowIndexProperty(lookupProperty[eRow]);
282  Tables[i]->SetColumnIndexProperty(lookupProperty[eColumn]);
283  tableData = el->FindNextElement("tableData");
284  }
285 
286  Debug(0);
287  break;
288  default:
289  cout << "No dimension given" << endl;
290  break;
291  }
292 
293  // Sanity checks: lookup indices must be increasing monotonically
294  unsigned int r,c,b;
295 
296  // find next xml element containing a name attribute
297  // to indicate where the error occured
298  Element* nameel = el;
299  while (nameel != 0 && nameel->GetAttributeValue("name") == "")
300  nameel=nameel->GetParent();
301 
302  // check breakpoints, if applicable
303  if (dimension > 2) {
304  for (b=2; b<=nTables; ++b) {
305  if (Data[b][1] <= Data[b-1][1]) {
306  stringstream errormsg;
307  errormsg << fgred << highint << endl
308  << " FGTable: breakpoint lookup is not monotonically increasing" << endl
309  << " in breakpoint " << b;
310  if (nameel != 0) errormsg << " of table in " << nameel->GetAttributeValue("name");
311  errormsg << ":" << reset << endl
312  << " " << Data[b][1] << "<=" << Data[b-1][1] << endl;
313  throw(errormsg.str());
314  }
315  }
316  }
317 
318  // check columns, if applicable
319  if (dimension > 1) {
320  for (c=2; c<=nCols; ++c) {
321  if (Data[0][c] <= Data[0][c-1]) {
322  stringstream errormsg;
323  errormsg << fgred << highint << endl
324  << " FGTable: column lookup is not monotonically increasing" << endl
325  << " in column " << c;
326  if (nameel != 0) errormsg << " of table in " << nameel->GetAttributeValue("name");
327  errormsg << ":" << reset << endl
328  << " " << Data[0][c] << "<=" << Data[0][c-1] << endl;
329  throw(errormsg.str());
330  }
331  }
332  }
333 
334  // check rows
335  if (dimension < 3) { // in 3D tables, check only rows of subtables
336  for (r=2; r<=nRows; ++r) {
337  if (Data[r][0]<=Data[r-1][0]) {
338  stringstream errormsg;
339  errormsg << fgred << highint << endl
340  << " FGTable: row lookup is not monotonically increasing" << endl
341  << " in row " << r;
342  if (nameel != 0) errormsg << " of table in " << nameel->GetAttributeValue("name");
343  errormsg << ":" << reset << endl
344  << " " << Data[r][0] << "<=" << Data[r-1][0] << endl;
345  throw(errormsg.str());
346  }
347  }
348  }
349 
350  bind();
351 
352  if (debug_lvl & 1) Print();
353 }
354 
355 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 
357 double** FGTable::Allocate(void)
358 {
359  Data = new double*[nRows+1];
360  for (unsigned int r=0; r<=nRows; r++) {
361  Data[r] = new double[nCols+1];
362  for (unsigned int c=0; c<=nCols; c++) {
363  Data[r][c] = 0.0;
364  }
365  }
366  return Data;
367 }
368 
369 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 
372 {
373  if (nTables > 0) {
374  for (unsigned int i=0; i<nTables; i++) delete Tables[i];
375  Tables.clear();
376  }
377  for (unsigned int r=0; r<=nRows; r++) delete[] Data[r];
378  delete[] Data;
379 
380  Debug(1);
381 }
382 
383 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 
385 unsigned int FGTable::FindNumColumns(const string& test_line)
386 {
387  // determine number of data columns in table (first column is row lookup - don't count)
388  size_t position=0;
389  unsigned int nCols=0;
390  while ((position = test_line.find_first_not_of(" \t", position)) != string::npos) {
391  nCols++;
392  position = test_line.find_first_of(" \t", position);
393  }
394  return nCols;
395 }
396 
397 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 
399 double FGTable::GetValue(void) const
400 {
401  double temp = 0;
402  double temp2 = 0;
403 
404  switch (Type) {
405  case tt1D:
406  temp = lookupProperty[eRow]->getDoubleValue();
407  temp2 = GetValue(temp);
408  return temp2;
409  case tt2D:
410  return GetValue(lookupProperty[eRow]->getDoubleValue(),
411  lookupProperty[eColumn]->getDoubleValue());
412  case tt3D:
413  return GetValue(lookupProperty[eRow]->getDoubleValue(),
414  lookupProperty[eColumn]->getDoubleValue(),
415  lookupProperty[eTable]->getDoubleValue());
416  default:
417  cerr << "Attempted to GetValue() for invalid/unknown table type" << endl;
418  throw(string("Attempted to GetValue() for invalid/unknown table type"));
419  }
420 }
421 
422 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
423 
424 double FGTable::GetValue(double key) const
425 {
426  double Factor, Value, Span;
427  unsigned int r = lastRowIndex;
428 
429  //if the key is off the end of the table, just return the
430  //end-of-table value, do not extrapolate
431  if( key <= Data[1][0] ) {
432  lastRowIndex=2;
433  //cout << "Key underneath table: " << key << endl;
434  return Data[1][1];
435  } else if ( key >= Data[nRows][0] ) {
436  lastRowIndex=nRows;
437  //cout << "Key over table: " << key << endl;
438  return Data[nRows][1];
439  }
440 
441  // the key is somewhere in the middle, search for the right breakpoint
442  // The search is particularly efficient if
443  // the correct breakpoint has not changed since last frame or
444  // has only changed very little
445 
446  while (r > 2 && Data[r-1][0] > key) { r--; }
447  while (r < nRows && Data[r][0] < key) { r++; }
448 
449  lastRowIndex=r;
450  // make sure denominator below does not go to zero.
451 
452  Span = Data[r][0] - Data[r-1][0];
453  if (Span != 0.0) {
454  Factor = (key - Data[r-1][0]) / Span;
455  if (Factor > 1.0) Factor = 1.0;
456  } else {
457  Factor = 1.0;
458  }
459 
460  Value = Factor*(Data[r][1] - Data[r-1][1]) + Data[r-1][1];
461 
462  return Value;
463 }
464 
465 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
466 
467 double FGTable::GetValue(double rowKey, double colKey) const
468 {
469  double rFactor, cFactor, col1temp, col2temp, Value;
470  unsigned int r = lastRowIndex;
471  unsigned int c = lastColumnIndex;
472 
473  while(r > 2 && Data[r-1][0] > rowKey) { r--; }
474  while(r < nRows && Data[r] [0] < rowKey) { r++; }
475 
476  while(c > 2 && Data[0][c-1] > colKey) { c--; }
477  while(c < nCols && Data[0][c] < colKey) { c++; }
478 
479  lastRowIndex=r;
480  lastColumnIndex=c;
481 
482  rFactor = (rowKey - Data[r-1][0]) / (Data[r][0] - Data[r-1][0]);
483  cFactor = (colKey - Data[0][c-1]) / (Data[0][c] - Data[0][c-1]);
484 
485  if (rFactor > 1.0) rFactor = 1.0;
486  else if (rFactor < 0.0) rFactor = 0.0;
487 
488  if (cFactor > 1.0) cFactor = 1.0;
489  else if (cFactor < 0.0) cFactor = 0.0;
490 
491  col1temp = rFactor*(Data[r][c-1] - Data[r-1][c-1]) + Data[r-1][c-1];
492  col2temp = rFactor*(Data[r][c] - Data[r-1][c]) + Data[r-1][c];
493 
494  Value = col1temp + cFactor*(col2temp - col1temp);
495 
496  return Value;
497 }
498 
499 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500 
501 double FGTable::GetValue(double rowKey, double colKey, double tableKey) const
502 {
503  double Factor, Value, Span;
504  unsigned int r = lastRowIndex;
505 
506  //if the key is off the end (or before the beginning) of the table,
507  // just return the boundary-table value, do not extrapolate
508 
509  if( tableKey <= Data[1][1] ) {
510  lastRowIndex=2;
511  return Tables[0]->GetValue(rowKey, colKey);
512  } else if ( tableKey >= Data[nRows][1] ) {
513  lastRowIndex=nRows;
514  return Tables[nRows-1]->GetValue(rowKey, colKey);
515  }
516 
517  // the key is somewhere in the middle, search for the right breakpoint
518  // The search is particularly efficient if
519  // the correct breakpoint has not changed since last frame or
520  // has only changed very little
521 
522  while(r > 2 && Data[r-1][1] > tableKey) { r--; }
523  while(r < nRows && Data[r] [1] < tableKey) { r++; }
524 
525  lastRowIndex=r;
526  // make sure denominator below does not go to zero.
527 
528  Span = Data[r][1] - Data[r-1][1];
529  if (Span != 0.0) {
530  Factor = (tableKey - Data[r-1][1]) / Span;
531  if (Factor > 1.0) Factor = 1.0;
532  } else {
533  Factor = 1.0;
534  }
535 
536  Value = Factor*(Tables[r-1]->GetValue(rowKey, colKey) - Tables[r-2]->GetValue(rowKey, colKey))
537  + Tables[r-2]->GetValue(rowKey, colKey);
538 
539  return Value;
540 }
541 
542 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
543 
544 void FGTable::operator<<(istream& in_stream)
545 {
546  int startRow=0;
547  int startCol=0;
548 
549 // In 1D table, no pseudo-row of column-headers (i.e. keys):
550  if (Type == tt1D) startRow = 1;
551 
552  for (unsigned int r=startRow; r<=nRows; r++) {
553  for (unsigned int c=startCol; c<=nCols; c++) {
554  if (r != 0 || c != 0) {
555  in_stream >> Data[r][c];
556  }
557  }
558  }
559 }
560 
561 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562 
563 // Put some error handling in here if trying to access out of range row, col.
564 
565 FGTable& FGTable::operator<<(const double n)
566 {
567  Data[rowCounter][colCounter] = n;
568  if (colCounter == (int)nCols) {
569  colCounter = 0;
570  rowCounter++;
571  } else {
572  colCounter++;
573  }
574  return *this;
575 }
576 
577 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578 
579 FGTable& FGTable::operator<<(const int n)
580 {
581  *this << (double)n;
582  return *this;
583 }
584 
585 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
586 
587 void FGTable::Print(void)
588 {
589  int startRow=0;
590  int startCol=0;
591 
592  if (Type == tt1D || Type == tt3D) startRow = 1;
593  if (Type == tt3D) startCol = 1;
594 
595 #if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
596  unsigned long flags = cout.setf(ios::fixed);
597 #else
598  ios::fmtflags flags = cout.setf(ios::fixed); // set up output stream
599 #endif
600 
601  switch(Type) {
602  case tt1D:
603  cout << " 1 dimensional table with " << nRows << " rows." << endl;
604  break;
605  case tt2D:
606  cout << " 2 dimensional table with " << nRows << " rows, " << nCols << " columns." << endl;
607  break;
608  case tt3D:
609  cout << " 3 dimensional table with " << nRows << " rows, "
610  << nCols << " columns "
611  << nTables << " tables." << endl;
612  break;
613  }
614  cout.precision(4);
615  for (unsigned int r=startRow; r<=nRows; r++) {
616  cout << " ";
617  for (unsigned int c=startCol; c<=nCols; c++) {
618  if (r == 0 && c == 0) {
619  cout << " ";
620  } else {
621  cout << Data[r][c] << " ";
622  if (Type == tt3D) {
623  cout << endl;
624  Tables[r-1]->Print();
625  }
626  }
627  }
628  cout << endl;
629  }
630  cout.setf(flags); // reset
631 }
632 
633 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
634 
635 void FGTable::bind(void)
636 {
637  typedef double (FGTable::*PMF)(void) const;
638  if ( !Name.empty() && !internal) {
639  string tmp = PropertyManager->mkPropertyName(Name, false); // Allow upper
640  PropertyManager->Tie( tmp, this, (PMF)&FGTable::GetValue);
641  }
642 }
643 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
644 // The bitmasked value choices are as follows:
645 // unset: In this case (the default) JSBSim would only print
646 // out the normally expected messages, essentially echoing
647 // the config files as they are read. If the environment
648 // variable is not set, debug_lvl is set to 1 internally
649 // 0: This requests JSBSim not to output any messages
650 // whatsoever.
651 // 1: This value explicity requests the normal JSBSim
652 // startup messages
653 // 2: This value asks for a message to be printed out when
654 // a class is instantiated
655 // 4: When this value is set, a message is displayed when a
656 // FGModel object executes its Run() method
657 // 8: When this value is set, various runtime state variables
658 // are printed out periodically
659 // 16: When set various parameters are sanity checked and
660 // a message is printed out when they go out of bounds
661 
662 void FGTable::Debug(int from)
663 {
664  if (debug_lvl <= 0) return;
665 
666  if (debug_lvl & 1) { // Standard console startup message output
667  if (from == 0) { // Constructor
668 
669  }
670  }
671  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
672  if (from == 0) cout << "Instantiated: FGTable" << endl;
673  if (from == 1) cout << "Destroyed: FGTable" << endl;
674  }
675  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
676  }
677  if (debug_lvl & 8 ) { // Runtime state variables
678  }
679  if (debug_lvl & 16) { // Sanity checking
680  }
681  if (debug_lvl & 64) {
682  if (from == 0) { // Constructor
683  cout << IdSrc << endl;
684  cout << IdHdr << endl;
685  }
686  }
687 }
688 }
Element * GetParent(void)
Returns a pointer to the parent of an element.
Definition: FGXMLElement.h:231
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
std::string mkPropertyName(std::string name, bool lowercase)
Property-ify a name replaces spaces with &#39;-&#39; and, optionally, makes name all lower case...
Class wrapper for property handling.
static char reset[5]
resets text properties
Definition: FGJSBBase.h:131
STL namespace.
Element * FindElement(const std::string &el="")
Searches for a specified element.
void operator<<(std::istream &)
Read the table in.
Definition: FGTable.cpp:544
unsigned int GetNumDataLines(void)
Returns the number of lines of data stored.
Definition: FGXMLElement.h:195
static char fgred[6]
red text
Definition: FGJSBBase.h:141
FGTable(const FGTable &table)
This is the very important copy constructor.
Definition: FGTable.cpp:85
void Tie(const std::string &name, bool *pointer, bool useDefault=true)
Tie a property to an external bool variable.
static char fgdef[6]
default text
Definition: FGJSBBase.h:145
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
const std::string & GetName(void) const
Retrieves the element name.
Definition: FGXMLElement.h:186
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to an element.
unsigned int GetNumElements(void)
Returns the number of child elements for this element.
Definition: FGXMLElement.h:198
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
static char highint[5]
highlights text
Definition: FGJSBBase.h:125
~FGTable()
Destructor.
Definition: FGTable.cpp:371
Lookup table class.
Definition: FGTable.h:243