FlightGear next
FGTable.cpp
Go to the documentation of this file.
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
12 Software Foundation; either version 2 of the License, or (at your option) any
13 later 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
21 with this program; if not, write to the Free Software Foundation, Inc., 59
22 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 Further information about the GNU Lesser General Public License can also be
25 found on the world wide web at http://www.gnu.org.
26
27FUNCTIONAL DESCRIPTION
28--------------------------------------------------------------------------------
29Models a lookup table
30
31HISTORY
32--------------------------------------------------------------------------------
33JSB 1/9/00 Created
34
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36INCLUDES
37%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38
39#include <assert.h>
40
41#include "FGTable.h"
43
44using namespace std;
45
46namespace JSBSim {
47
48/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
49CLASS IMPLEMENTATION
50%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
51
53 : nRows(NRows), nCols(1), PropertyManager(nullptr)
54{
55 Type = tt1D;
56 colCounter = 0;
57 rowCounter = 1;
58 nTables = 0;
59
60 Data = Allocate();
61 Debug(0);
62 lastRowIndex=lastColumnIndex=2;
63}
64
65//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66
67FGTable::FGTable(int NRows, int NCols)
68 : nRows(NRows), nCols(NCols), PropertyManager(nullptr)
69{
70 Type = tt2D;
71 colCounter = 1;
72 rowCounter = 0;
73 nTables = 0;
74
75 Data = Allocate();
76 Debug(0);
77 lastRowIndex=lastColumnIndex=2;
78}
79
80//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81
82FGTable::FGTable(const FGTable& t) : PropertyManager(t.PropertyManager)
83{
84 Type = t.Type;
85 colCounter = t.colCounter;
86 rowCounter = t.rowCounter;
87 tableCounter = t.tableCounter;
88 nRows = t.nRows;
89 nCols = t.nCols;
90 nTables = t.nTables;
91 dimension = t.dimension;
92 internal = t.internal;
93 Name = t.Name;
94 lookupProperty[0] = t.lookupProperty[0];
95 lookupProperty[1] = t.lookupProperty[1];
96 lookupProperty[2] = t.lookupProperty[2];
97
98 Tables = t.Tables;
99 Data = Allocate();
100 for (unsigned int r=0; r<=nRows; r++) {
101 for (unsigned int c=0; c<=nCols; c++) {
102 Data[r][c] = t.Data[r][c];
103 }
104 }
105 lastRowIndex = t.lastRowIndex;
106 lastColumnIndex = t.lastColumnIndex;
107 lastTableIndex = t.lastTableIndex;
108}
109
110//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
111
112unsigned int FindNumColumns(const string& test_line)
113{
114 // determine number of data columns in table (first column is row lookup - don't count)
115 size_t position=0;
116 unsigned int nCols=0;
117 while ((position = test_line.find_first_not_of(" \t", position)) != string::npos) {
118 nCols++;
119 position = test_line.find_first_of(" \t", position);
120 }
121 return nCols;
122}
123
124//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125
127 const std::string& Prefix)
128 : PropertyManager(propMan)
129{
130 unsigned int i;
131
132 stringstream buf;
133 string brkpt_string;
134 Element *tableData = nullptr;
135 string operation_types = "function, product, sum, difference, quotient,"
136 "pow, abs, sin, cos, asin, acos, tan, atan, table";
137
138 nTables = 0;
139
140 // Is this an internal lookup table?
141
142 internal = false;
143 Name = el->GetAttributeValue("name"); // Allow this table to be named with a property
144 string call_type = el->GetAttributeValue("type");
145 if (call_type == string("internal")) {
146 Element* parent_element = el->GetParent();
147 string parent_type = parent_element->GetName();
148 if (operation_types.find(parent_type) == string::npos) {
149 internal = true;
150 } else {
151 // internal table is a child element of a restricted type
152 std::cerr << el->ReadFrom()
153 << " An internal table cannot be nested within another type,"
154 << " such as a function. The 'internal' keyword of table "
155 << Name << "is ignored." << endl;
156 }
157 } else if (!call_type.empty()) {
158 std::cerr << el->ReadFrom()
159 <<" An unknown table type attribute is listed: " << call_type
160 << endl;
161 throw BaseException("Unknown table type.");
162 }
163
164 // Determine and store the lookup properties for this table unless this table
165 // is part of a 3D table, in which case its independentVar property indexes
166 // will be set by a call from the owning table during creation
167
168 dimension = 0;
169
170 Element* axisElement = el->FindElement("independentVar");
171 if (axisElement) {
172
173 // The 'internal' attribute of the table element cannot be specified
174 // at the same time that independentVars are specified.
175 if (internal) {
176 cerr << el->ReadFrom()
177 << fgred << " This table specifies both 'internal' call type" << endl
178 << " and specific lookup properties via the 'independentVar' element." << endl
179 << " These are mutually exclusive specifications. The 'internal'" << endl
180 << " attribute will be ignored." << fgdef << endl << endl;
181 internal = false;
182 }
183
184 while (axisElement) {
185 string property_string = axisElement->GetDataLine();
186 if (property_string.find("#") != string::npos) {
187 if (is_number(Prefix)) {
188 property_string = replace(property_string,"#",Prefix);
189 }
190 }
191
192 FGPropertyValue_ptr node = new FGPropertyValue(property_string,
193 PropertyManager);
194 string lookup_axis = axisElement->GetAttributeValue("lookup");
195 if (lookup_axis == string("row")) {
196 lookupProperty[eRow] = node;
197 } else if (lookup_axis == string("column")) {
198 lookupProperty[eColumn] = node;
199 } else if (lookup_axis == string("table")) {
200 lookupProperty[eTable] = node;
201 } else if (!lookup_axis.empty()) {
202 throw BaseException("Lookup table axis specification not understood: " + lookup_axis);
203 } else { // assumed single dimension table; row lookup
204 lookupProperty[eRow] = node;
205 }
206 dimension++;
207 axisElement = el->FindNextElement("independentVar");
208 }
209
210 } else if (internal) { // This table is an internal table
211
212 // determine how many rows, columns, and tables in this table (dimension).
213
214 if (el->GetNumElements("tableData") > 1) {
215 dimension = 3; // this is a 3D table
216 } else {
217 tableData = el->FindElement("tableData");
218 string test_line = tableData->GetDataLine(1); // examine second line in table for dimension
219 if (FindNumColumns(test_line) == 2) dimension = 1; // 1D table
220 else if (FindNumColumns(test_line) > 2) dimension = 2; // 2D table
221 else {
222 std::cerr << tableData->ReadFrom()
223 << "Invalid number of columns in table" << endl;
224 }
225 }
226
227 } else {
228 brkpt_string = el->GetAttributeValue("breakPoint");
229 if (brkpt_string.empty()) {
230 // no independentVars found, and table is not marked as internal, nor is it
231 // a 3D table
232 std::cerr << el->ReadFrom()
233 << "No independentVars found, and table is not marked as internal,"
234 << " nor is it a 3D table." << endl;
235 throw BaseException("No independent variable found for table.");
236 }
237 }
238 // end lookup property code
239
240 if (brkpt_string.empty()) { // Not a 3D table "table element"
241 tableData = el->FindElement("tableData");
242 } else { // This is a table in a 3D table
243 tableData = el;
244 dimension = 2; // Currently, infers 2D table
245 }
246
247 for (i=0; i<tableData->GetNumDataLines(); i++) {
248 string line = tableData->GetDataLine(i);
249 if (line.find_first_not_of("0123456789.-+eE \t\n") != string::npos) {
250 cerr << " In file " << tableData->GetFileName() << endl
251 << " Illegal character found in line "
252 << tableData->GetLineNumber() + i + 1 << ": " << endl << line << endl;
253 throw BaseException("Illegal character");
254 }
255 buf << line << " ";
256 }
257
258 switch (dimension) {
259 case 1:
260 nRows = tableData->GetNumDataLines();
261 nCols = 1;
262 Type = tt1D;
263 colCounter = 0;
264 rowCounter = 1;
265 Data = Allocate();
266 Debug(0);
267 lastRowIndex = lastColumnIndex = 2;
268 *this << buf;
269 break;
270 case 2:
271 nRows = tableData->GetNumDataLines()-1;
272
273 if (nRows >= 2) {
274 nCols = FindNumColumns(tableData->GetDataLine(0));
275 if (nCols < 2) {
276 std::cerr << tableData->ReadFrom()
277 << "Not enough columns in table data" << endl;
278 throw BaseException("Not enough columns in table data.");
279 }
280 } else {
281 std::cerr << tableData->ReadFrom()
282 << "Not enough rows in table data" << endl;
283 throw BaseException("Not enough rows in the table data.");
284 }
285
286 Type = tt2D;
287 colCounter = 1;
288 rowCounter = 0;
289
290 Data = Allocate();
291 lastRowIndex = lastColumnIndex = 2;
292 *this << buf;
293 break;
294 case 3:
295 nTables = el->GetNumElements("tableData");
296 nRows = nTables;
297 nCols = 1;
298 Type = tt3D;
299 colCounter = 1;
300 rowCounter = 1;
301 lastRowIndex = lastColumnIndex = 2;
302
303 Data = Allocate(); // this data array will contain the keys for the associated tables
304 Tables.reserve(nTables); // necessary?
305 tableData = el->FindElement("tableData");
306 for (i=0; i<nTables; i++) {
307 Tables.push_back(new FGTable(PropertyManager, tableData));
308 Data[i+1][1] = tableData->GetAttributeValueAsNumber("breakPoint");
309 Tables[i]->lookupProperty[eRow] = lookupProperty[eRow];
310 Tables[i]->lookupProperty[eColumn] = lookupProperty[eColumn];
311 tableData = el->FindNextElement("tableData");
312 }
313
314 Debug(0);
315 break;
316 default:
317 cout << "No dimension given" << endl;
318 break;
319 }
320
321 // Sanity checks: lookup indices must be increasing monotonically
322 unsigned int r,c,b;
323
324 // find next xml element containing a name attribute
325 // to indicate where the error occured
326 Element* nameel = el;
327 while (nameel != 0 && nameel->GetAttributeValue("name") == "")
328 nameel=nameel->GetParent();
329
330 // check breakpoints, if applicable
331 if (dimension > 2) {
332 for (b=2; b<=nTables; ++b) {
333 if (Data[b][1] <= Data[b-1][1]) {
334 std::cerr << el->ReadFrom()
335 << fgred << highint
336 << " FGTable: breakpoint lookup is not monotonically increasing" << endl
337 << " in breakpoint " << b;
338 if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
339 std::cerr << ":" << reset << endl
340 << " " << Data[b][1] << "<=" << Data[b-1][1] << endl;
341 throw BaseException("Breakpoint lookup is not monotonically increasing");
342 }
343 }
344 }
345
346 // check columns, if applicable
347 if (dimension > 1) {
348 for (c=2; c<=nCols; ++c) {
349 if (Data[0][c] <= Data[0][c-1]) {
350 std::cerr << el->ReadFrom()
351 << fgred << highint
352 << " FGTable: column lookup is not monotonically increasing" << endl
353 << " in column " << c;
354 if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
355 std::cerr << ":" << reset << endl
356 << " " << Data[0][c] << "<=" << Data[0][c-1] << endl;
357 throw BaseException("FGTable: column lookup is not monotonically increasing");
358 }
359 }
360 }
361
362 // check rows
363 if (dimension < 3) { // in 3D tables, check only rows of subtables
364 for (r=2; r<=nRows; ++r) {
365 if (Data[r][0]<=Data[r-1][0]) {
366 std::cerr << el->ReadFrom()
367 << fgred << highint
368 << " FGTable: row lookup is not monotonically increasing" << endl
369 << " in row " << r;
370 if (nameel != 0) std::cerr << " of table in " << nameel->GetAttributeValue("name");
371 std::cerr << ":" << reset << endl
372 << " " << Data[r][0] << "<=" << Data[r-1][0] << endl;
373 throw BaseException("FGTable: row lookup is not monotonically increasing");
374 }
375 }
376 }
377
378 bind(el, Prefix);
379
380 if (debug_lvl & 1) Print();
381}
382
383//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384
385double** FGTable::Allocate(void)
386{
387 Data = new double*[nRows+1];
388 for (unsigned int r=0; r<=nRows; r++) {
389 Data[r] = new double[nCols+1];
390 for (unsigned int c=0; c<=nCols; c++) {
391 Data[r][c] = 0.0;
392 }
393 }
394 return Data;
395}
396
397//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398
400{
401 // Untie the bound property so that it makes no further reference to this
402 // instance of FGTable after the destruction is completed.
403 if (!Name.empty() && !internal) {
404 string tmp = PropertyManager->mkPropertyName(Name, false);
405 FGPropertyNode* node = PropertyManager->GetNode(tmp);
406 if (node && node->isTied())
407 PropertyManager->Untie(node);
408 }
409
410 if (nTables > 0) {
411 for (unsigned int i=0; i<nTables; i++) delete Tables[i];
412 Tables.clear();
413 }
414 for (unsigned int r=0; r<=nRows; r++) delete[] Data[r];
415 delete[] Data;
416
417 Debug(1);
418}
419
420//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421
422double FGTable::GetValue(void) const
423{
424 double temp = 0;
425 double temp2 = 0;
426
427 switch (Type) {
428 case tt1D:
429 assert(lookupProperty[eRow]);
430 temp = lookupProperty[eRow]->getDoubleValue();
431 temp2 = GetValue(temp);
432 return temp2;
433 case tt2D:
434 assert(lookupProperty[eRow]);
435 assert(lookupProperty[eColumn]);
436 return GetValue(lookupProperty[eRow]->getDoubleValue(),
437 lookupProperty[eColumn]->getDoubleValue());
438 case tt3D:
439 assert(lookupProperty[eRow]);
440 assert(lookupProperty[eColumn]);
441 assert(lookupProperty[eTable]);
442 return GetValue(lookupProperty[eRow]->getDoubleValue(),
443 lookupProperty[eColumn]->getDoubleValue(),
444 lookupProperty[eTable]->getDoubleValue());
445 default:
446 cerr << "Attempted to GetValue() for invalid/unknown table type" << endl;
447 throw(string("Attempted to GetValue() for invalid/unknown table type"));
448 }
449}
450
451//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452
453double FGTable::GetValue(double key) const
454{
455 double Factor, Value, Span;
456 unsigned int r = lastRowIndex;
457
458 //if the key is off the end of the table, just return the
459 //end-of-table value, do not extrapolate
460 if( key <= Data[1][0] ) {
461 lastRowIndex=2;
462 //cout << "Key underneath table: " << key << endl;
463 return Data[1][1];
464 } else if ( key >= Data[nRows][0] ) {
465 lastRowIndex=nRows;
466 //cout << "Key over table: " << key << endl;
467 return Data[nRows][1];
468 }
469
470 // the key is somewhere in the middle, search for the right breakpoint
471 // The search is particularly efficient if
472 // the correct breakpoint has not changed since last frame or
473 // has only changed very little
474
475 while (r > 2 && Data[r-1][0] > key) { r--; }
476 while (r < nRows && Data[r][0] < key) { r++; }
477
478 lastRowIndex=r;
479 // make sure denominator below does not go to zero.
480
481 Span = Data[r][0] - Data[r-1][0];
482 if (Span != 0.0) {
483 Factor = (key - Data[r-1][0]) / Span;
484 if (Factor > 1.0) Factor = 1.0;
485 } else {
486 Factor = 1.0;
487 }
488
489 Value = Factor*(Data[r][1] - Data[r-1][1]) + Data[r-1][1];
490
491 return Value;
492}
493
494//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495
496double FGTable::GetValue(double rowKey, double colKey) const
497{
498 double rFactor, cFactor, col1temp, col2temp, Value;
499 unsigned int r = lastRowIndex;
500 unsigned int c = lastColumnIndex;
501
502 while(r > 2 && Data[r-1][0] > rowKey) { r--; }
503 while(r < nRows && Data[r] [0] < rowKey) { r++; }
504
505 while(c > 2 && Data[0][c-1] > colKey) { c--; }
506 while(c < nCols && Data[0][c] < colKey) { c++; }
507
508 lastRowIndex=r;
509 lastColumnIndex=c;
510
511 rFactor = (rowKey - Data[r-1][0]) / (Data[r][0] - Data[r-1][0]);
512 cFactor = (colKey - Data[0][c-1]) / (Data[0][c] - Data[0][c-1]);
513
514 if (rFactor > 1.0) rFactor = 1.0;
515 else if (rFactor < 0.0) rFactor = 0.0;
516
517 if (cFactor > 1.0) cFactor = 1.0;
518 else if (cFactor < 0.0) cFactor = 0.0;
519
520 col1temp = rFactor*(Data[r][c-1] - Data[r-1][c-1]) + Data[r-1][c-1];
521 col2temp = rFactor*(Data[r][c] - Data[r-1][c]) + Data[r-1][c];
522
523 Value = col1temp + cFactor*(col2temp - col1temp);
524
525 return Value;
526}
527
528//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
529
530double FGTable::GetValue(double rowKey, double colKey, double tableKey) const
531{
532 double Factor, Value, Span;
533 unsigned int r = lastRowIndex;
534
535 //if the key is off the end (or before the beginning) of the table,
536 // just return the boundary-table value, do not extrapolate
537
538 if( tableKey <= Data[1][1] ) {
539 lastRowIndex=2;
540 return Tables[0]->GetValue(rowKey, colKey);
541 } else if ( tableKey >= Data[nRows][1] ) {
542 lastRowIndex=nRows;
543 return Tables[nRows-1]->GetValue(rowKey, colKey);
544 }
545
546 // the key is somewhere in the middle, search for the right breakpoint
547 // The search is particularly efficient if
548 // the correct breakpoint has not changed since last frame or
549 // has only changed very little
550
551 while(r > 2 && Data[r-1][1] > tableKey) { r--; }
552 while(r < nRows && Data[r] [1] < tableKey) { r++; }
553
554 lastRowIndex=r;
555 // make sure denominator below does not go to zero.
556
557 Span = Data[r][1] - Data[r-1][1];
558 if (Span != 0.0) {
559 Factor = (tableKey - Data[r-1][1]) / Span;
560 if (Factor > 1.0) Factor = 1.0;
561 } else {
562 Factor = 1.0;
563 }
564
565 Value = Factor*(Tables[r-1]->GetValue(rowKey, colKey) - Tables[r-2]->GetValue(rowKey, colKey))
566 + Tables[r-2]->GetValue(rowKey, colKey);
567
568 return Value;
569}
570
571//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
572
573void FGTable::operator<<(istream& in_stream)
574{
575 int startRow=0;
576 int startCol=0;
577
578// In 1D table, no pseudo-row of column-headers (i.e. keys):
579 if (Type == tt1D) startRow = 1;
580
581 for (unsigned int r=startRow; r<=nRows; r++) {
582 for (unsigned int c=startCol; c<=nCols; c++) {
583 if (r != 0 || c != 0) {
584 in_stream >> Data[r][c];
585 }
586 }
587 }
588}
589
590//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591
592// Put some error handling in here if trying to access out of range row, col.
593
595{
596 Data[rowCounter][colCounter] = n;
597 if (colCounter == (int)nCols) {
598 colCounter = 0;
599 rowCounter++;
600 } else {
601 colCounter++;
602 }
603 return *this;
604}
605
606//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
607
609{
610 *this << (double)n;
611 return *this;
612}
613
614//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
615
617{
618 int startRow=0;
619 int startCol=0;
620
621 if (Type == tt1D || Type == tt3D) startRow = 1;
622 if (Type == tt3D) startCol = 1;
623
624#if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
625 unsigned long flags = cout.setf(ios::fixed);
626#else
627 ios::fmtflags flags = cout.setf(ios::fixed); // set up output stream
628#endif
629
630 switch(Type) {
631 case tt1D:
632 cout << " 1 dimensional table with " << nRows << " rows." << endl;
633 break;
634 case tt2D:
635 cout << " 2 dimensional table with " << nRows << " rows, " << nCols << " columns." << endl;
636 break;
637 case tt3D:
638 cout << " 3 dimensional table with " << nRows << " rows, "
639 << nCols << " columns "
640 << nTables << " tables." << endl;
641 break;
642 }
643 cout.precision(4);
644 for (unsigned int r=startRow; r<=nRows; r++) {
645 cout << " ";
646 for (unsigned int c=startCol; c<=nCols; c++) {
647 if (r == 0 && c == 0) {
648 cout << " ";
649 } else {
650 cout << Data[r][c] << " ";
651 if (Type == tt3D) {
652 cout << endl;
653 Tables[r-1]->Print();
654 }
655 }
656 }
657 cout << endl;
658 }
659 cout.setf(flags); // reset
660}
661
662//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
663
664void FGTable::bind(Element* el, const string& Prefix)
665{
666 typedef double (FGTable::*PMF)(void) const;
667
668 if ( !Name.empty() && !internal) {
669 if (!Prefix.empty()) {
670 if (is_number(Prefix)) {
671 if (Name.find("#") != string::npos) { // if "#" is found
672 Name = replace(Name, "#", Prefix);
673 } else {
674 cerr << el->ReadFrom()
675 << "Malformed table name with number: " << Prefix
676 << " and property name: " << Name
677 << " but no \"#\" sign for substitution." << endl;
678 }
679 } else {
680 Name = Prefix + "/" + Name;
681 }
682 }
683 string tmp = PropertyManager->mkPropertyName(Name, false);
684
685 if (PropertyManager->HasNode(tmp)) {
686 FGPropertyNode* _property = PropertyManager->GetNode(tmp);
687 if (_property->isTied()) {
688 cerr << el->ReadFrom()
689 << "Property " << tmp << " has already been successfully bound (late)." << endl;
690 throw("Failed to bind the property to an existing already tied node.");
691 }
692 }
693
694 PropertyManager->Tie(tmp, this, (PMF)&FGTable::GetValue);
695 }
696}
697//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
698// The bitmasked value choices are as follows:
699// unset: In this case (the default) JSBSim would only print
700// out the normally expected messages, essentially echoing
701// the config files as they are read. If the environment
702// variable is not set, debug_lvl is set to 1 internally
703// 0: This requests JSBSim not to output any messages
704// whatsoever.
705// 1: This value explicity requests the normal JSBSim
706// startup messages
707// 2: This value asks for a message to be printed out when
708// a class is instantiated
709// 4: When this value is set, a message is displayed when a
710// FGModel object executes its Run() method
711// 8: When this value is set, various runtime state variables
712// are printed out periodically
713// 16: When set various parameters are sanity checked and
714// a message is printed out when they go out of bounds
715
716void FGTable::Debug(int from)
717{
718 if (debug_lvl <= 0) return;
719
720 if (debug_lvl & 1) { // Standard console startup message output
721 if (from == 0) { // Constructor
722
723 }
724 }
725 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
726 if (from == 0) cout << "Instantiated: FGTable" << endl;
727 if (from == 1) cout << "Destroyed: FGTable" << endl;
728 }
729 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
730 }
731 if (debug_lvl & 8 ) { // Runtime state variables
732 }
733 if (debug_lvl & 16) { // Sanity checking
734 }
735 if (debug_lvl & 64) {
736 if (from == 0) { // Constructor
737 }
738 }
739}
740}
#define i(x)
const std::string & GetName(void) const
Retrieves the element name.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
unsigned int GetNumDataLines(void)
Returns the number of lines of data stored.
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
int GetLineNumber(void) const
Returns the line number at which the element has been defined.
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to an element.
Element * GetParent(void)
Returns a pointer to the parent of an element.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
unsigned int GetNumElements(void)
Returns the number of child elements for this element.
Element * FindElement(const std::string &el="")
Searches for a specified element.
const std::string & GetFileName(void) const
Returns the name of the file in which the element has been read.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
static char fgdef[6]
default text
Definition FGJSBBase.h:143
static char highint[5]
highlights text
Definition FGJSBBase.h:123
static char reset[5]
resets text properties
Definition FGJSBBase.h:129
static char fgred[6]
red text
Definition FGJSBBase.h:139
static short debug_lvl
Definition FGJSBBase.h:190
double getDoubleValue(void) const
Definition FGParameter.h:67
Class wrapper for property handling.
FGPropertyNode * GetNode(const std::string &path, bool create=false)
Get a property node.
Represents a property value which can use late binding.
Lookup table class.
Definition FGTable.h:234
double GetValue(void) const
Definition FGTable.cpp:422
void operator<<(std::istream &)
Read the table in.
FGTable(const FGTable &table)
This is the very important copy constructor.
Definition FGTable.cpp:82
void Print(void)
Definition FGTable.cpp:616
~FGTable()
Destructor.
Definition FGTable.cpp:399
SGSharedPtr< FGPropertyValue > FGPropertyValue_ptr
unsigned int FindNumColumns(const string &test_line)
Definition FGTable.cpp:112
bool is_number(const std::string &str)
std::string replace(std::string str, const std::string &old, const std::string &newstr)