42 #include "input_output/FGXMLElement.h"
52 FGTable::FGTable(
int NRows)
53 : nRows(NRows), nCols(1), PropertyManager(nullptr)
62 lastRowIndex=lastColumnIndex=2;
68 : nRows(NRows), nCols(NCols), PropertyManager(nullptr)
77 lastRowIndex=lastColumnIndex=2;
85 colCounter = t.colCounter;
86 rowCounter = t.rowCounter;
87 tableCounter = t.tableCounter;
91 dimension = t.dimension;
92 internal = t.internal;
94 lookupProperty[0] = t.lookupProperty[0];
95 lookupProperty[1] = t.lookupProperty[1];
96 lookupProperty[2] = t.lookupProperty[2];
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];
105 lastRowIndex = t.lastRowIndex;
106 lastColumnIndex = t.lastColumnIndex;
107 lastTableIndex = t.lastTableIndex;
112 unsigned int FindNumColumns(
const string& test_line)
116 unsigned int nCols=0;
117 while ((position = test_line.find_first_not_of(
" \t", position)) != string::npos) {
119 position = test_line.find_first_of(
" \t", position);
127 const std::string& Prefix)
128 : PropertyManager(propMan)
135 string operation_types =
"function, product, sum, difference, quotient,"
136 "pow, abs, sin, cos, asin, acos, tan, atan, table";
145 if (call_type ==
string(
"internal")) {
147 string parent_type = parent_element->
GetName();
148 if (operation_types.find(parent_type) == string::npos) {
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;
157 }
else if (!call_type.empty()) {
159 <<
" An unknown table type attribute is listed: " << call_type
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;
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);
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);
204 lookupProperty[eRow] = node;
210 }
else if (
internal) {
219 if (FindNumColumns(test_line) == 2) dimension = 1;
220 else if (FindNumColumns(test_line) > 2) dimension = 2;
223 <<
"Invalid number of columns in table" << endl;
229 if (brkpt_string.empty()) {
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.");
240 if (brkpt_string.empty()) {
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;
267 lastRowIndex = lastColumnIndex = 2;
277 <<
"Not enough columns in table data" << endl;
282 <<
"Not enough rows in table data" << endl;
291 lastRowIndex = lastColumnIndex = 2;
301 lastRowIndex = lastColumnIndex = 2;
304 Tables.reserve(nTables);
306 for (i=0; i<nTables; i++) {
307 Tables.push_back(
new FGTable(PropertyManager, tableData));
309 Tables[i]->lookupProperty[eRow] = lookupProperty[eRow];
310 Tables[i]->lookupProperty[eColumn] = lookupProperty[eColumn];
317 cout <<
"No dimension given" << endl;
332 for (b=2; b<=nTables; ++b) {
333 if (Data[b][1] <= Data[b-1][1]) {
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");
348 for (c=2; c<=nCols; ++c) {
349 if (Data[0][c] <= Data[0][c-1]) {
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");
364 for (r=2; r<=nRows; ++r) {
365 if (Data[r][0]<=Data[r-1][0]) {
368 <<
" FGTable: row lookup is not monotonically increasing" << endl
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");
380 if (debug_lvl & 1) Print();
385 double** FGTable::Allocate(
void)
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++) {
403 if (!Name.empty() && !
internal) {
406 if (node && node->isTied())
407 PropertyManager->
Untie(node);
411 for (
unsigned int i=0; i<nTables; i++)
delete Tables[i];
414 for (
unsigned int r=0; r<=nRows; r++)
delete[] Data[r];
422 double FGTable::GetValue(
void)
const
429 assert(lookupProperty[eRow]);
430 temp = lookupProperty[eRow]->getDoubleValue();
431 temp2 = GetValue(temp);
434 assert(lookupProperty[eRow]);
435 assert(lookupProperty[eColumn]);
436 return GetValue(lookupProperty[eRow]->getDoubleValue(),
437 lookupProperty[eColumn]->getDoubleValue());
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());
446 cerr <<
"Attempted to GetValue() for invalid/unknown table type" << endl;
447 throw(
string(
"Attempted to GetValue() for invalid/unknown table type"));
453 double FGTable::GetValue(
double key)
const
455 double Factor, Value, Span;
456 unsigned int r = lastRowIndex;
460 if( key <= Data[1][0] ) {
464 }
else if ( key >= Data[nRows][0] ) {
467 return Data[nRows][1];
475 while (r > 2 && Data[r-1][0] > key) { r--; }
476 while (r < nRows && Data[r][0] < key) { r++; }
481 Span = Data[r][0] - Data[r-1][0];
483 Factor = (key - Data[r-1][0]) / Span;
484 if (Factor > 1.0) Factor = 1.0;
489 Value = Factor*(Data[r][1] - Data[r-1][1]) + Data[r-1][1];
496 double FGTable::GetValue(
double rowKey,
double colKey)
const
498 double rFactor, cFactor, col1temp, col2temp, Value;
499 unsigned int r = lastRowIndex;
500 unsigned int c = lastColumnIndex;
502 while(r > 2 && Data[r-1][0] > rowKey) { r--; }
503 while(r < nRows && Data[r] [0] < rowKey) { r++; }
505 while(c > 2 && Data[0][c-1] > colKey) { c--; }
506 while(c < nCols && Data[0][c] < colKey) { c++; }
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]);
514 if (rFactor > 1.0) rFactor = 1.0;
515 else if (rFactor < 0.0) rFactor = 0.0;
517 if (cFactor > 1.0) cFactor = 1.0;
518 else if (cFactor < 0.0) cFactor = 0.0;
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];
523 Value = col1temp + cFactor*(col2temp - col1temp);
530 double FGTable::GetValue(
double rowKey,
double colKey,
double tableKey)
const
532 double Factor, Value, Span;
533 unsigned int r = lastRowIndex;
538 if( tableKey <= Data[1][1] ) {
540 return Tables[0]->GetValue(rowKey, colKey);
541 }
else if ( tableKey >= Data[nRows][1] ) {
543 return Tables[nRows-1]->GetValue(rowKey, colKey);
551 while(r > 2 && Data[r-1][1] > tableKey) { r--; }
552 while(r < nRows && Data[r] [1] < tableKey) { r++; }
557 Span = Data[r][1] - Data[r-1][1];
559 Factor = (tableKey - Data[r-1][1]) / Span;
560 if (Factor > 1.0) Factor = 1.0;
565 Value = Factor*(Tables[r-1]->GetValue(rowKey, colKey) - Tables[r-2]->GetValue(rowKey, colKey))
566 + Tables[r-2]->GetValue(rowKey, colKey);
579 if (Type == tt1D) startRow = 1;
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];
596 Data[rowCounter][colCounter] = n;
597 if (colCounter == (
int)nCols) {
616 void FGTable::Print(
void)
621 if (Type == tt1D || Type == tt3D) startRow = 1;
622 if (Type == tt3D) startCol = 1;
624 #if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
625 unsigned long flags = cout.setf(ios::fixed);
627 ios::fmtflags flags = cout.setf(ios::fixed);
632 cout <<
" 1 dimensional table with " << nRows <<
" rows." << endl;
635 cout <<
" 2 dimensional table with " << nRows <<
" rows, " << nCols <<
" columns." << endl;
638 cout <<
" 3 dimensional table with " << nRows <<
" rows, "
639 << nCols <<
" columns "
640 << nTables <<
" tables." << endl;
644 for (
unsigned int r=startRow; r<=nRows; r++) {
646 for (
unsigned int c=startCol; c<=nCols; c++) {
647 if (r == 0 && c == 0) {
650 cout << Data[r][c] <<
" ";
653 Tables[r-1]->Print();
664 void FGTable::bind(Element* el,
const string& Prefix)
666 typedef double (
FGTable::*PMF)(void)
const;
668 if ( !Name.empty() && !
internal) {
669 if (!Prefix.empty()) {
670 if (is_number(Prefix)) {
671 if (Name.find(
"#") != string::npos) {
672 Name = replace(Name,
"#", Prefix);
674 cerr << el->ReadFrom()
675 <<
"Malformed table name with number: " << Prefix
676 <<
" and property name: " << Name
677 <<
" but no \"#\" sign for substitution." << endl;
680 Name = Prefix +
"/" + Name;
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.");
694 PropertyManager->
Tie(tmp,
this, (PMF)&FGTable::GetValue);
716 void FGTable::Debug(
int from)
718 if (debug_lvl <= 0)
return;
725 if (debug_lvl & 2 ) {
726 if (from == 0) cout <<
"Instantiated: FGTable" << endl;
727 if (from == 1) cout <<
"Destroyed: FGTable" << endl;
729 if (debug_lvl & 4 ) {
731 if (debug_lvl & 8 ) {
733 if (debug_lvl & 16) {
735 if (debug_lvl & 64) {