JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGXMLElement.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Author: Jon Berndt
4  Date started: 09/28/2004
5  Purpose: XML element class
6  Called by: FGXMLParse
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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28 INCLUDES
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
30 
31 #include <cmath>
32 #include <cstdlib>
33 #include <iostream>
34 #include <sstream>
35 
36 #include "FGXMLElement.h"
37 #include "string_utilities.h"
38 #include "FGJSBBase.h"
39 
40 using namespace std;
41 
42 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 FORWARD DECLARATIONS
44 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
45 
46 namespace JSBSim {
47 
48 IDENT(IdSrc,"$Id: FGXMLElement.cpp,v 1.56 2016/09/11 11:26:04 bcoconni Exp $");
49 IDENT(IdHdr,ID_XMLELEMENT);
50 
51 bool Element::converterIsInitialized = false;
52 map <string, map <string, double> > Element::convert;
53 
54 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55 CLASS IMPLEMENTATION
56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
57 
58 Element::Element(const string& nm)
59 {
60  name = nm;
61  parent = 0L;
62  element_index = 0;
63  line_number = -1;
64 
65  if (!converterIsInitialized) {
66  converterIsInitialized = true;
67  // convert ["from"]["to"] = factor, so: from * factor = to
68  // Length
69  convert["M"]["FT"] = 3.2808399;
70  convert["FT"]["M"] = 1.0/convert["M"]["FT"];
71  convert["CM"]["FT"] = 0.032808399;
72  convert["FT"]["CM"] = 1.0/convert["CM"]["FT"];
73  convert["KM"]["FT"] = 3280.8399;
74  convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
75  convert["FT"]["IN"] = 12.0;
76  convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
77  convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
78  convert["M"]["IN"] = convert["M"]["FT"] * convert["FT"]["IN"];
79  // Area
80  convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
81  convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
82  convert["CM2"]["FT2"] = convert["CM"]["FT"]*convert["CM"]["FT"];
83  convert["FT2"]["CM2"] = 1.0/convert["CM2"]["FT2"];
84  convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
85  convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
86  convert["FT2"]["IN2"] = 144.0;
87  convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
88  // Volume
89  convert["IN3"]["CC"] = 16.387064;
90  convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
91  convert["FT3"]["IN3"] = 1728.0;
92  convert["IN3"]["FT3"] = 1.0/convert["FT3"]["IN3"];
93  convert["M3"]["FT3"] = 35.3146667;
94  convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"];
95  convert["LTR"]["IN3"] = 61.0237441;
96  convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"];
97  // Mass & Weight
98  convert["LBS"]["KG"] = 0.45359237;
99  convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
100  convert["SLUG"]["KG"] = 14.59390;
101  convert["KG"]["SLUG"] = 1.0/convert["SLUG"]["KG"];
102  // Moments of Inertia
103  convert["SLUG*FT2"]["KG*M2"] = 1.35594;
104  convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
105  // Angles
106  convert["RAD"]["DEG"] = 180.0/M_PI;
107  convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
108  // Angular rates
109  convert["RAD/SEC"]["DEG/SEC"] = convert["RAD"]["DEG"];
110  convert["DEG/SEC"]["RAD/SEC"] = 1.0/convert["RAD/SEC"]["DEG/SEC"];
111  // Spring force
112  convert["LBS/FT"]["N/M"] = 14.5939;
113  convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
114  // Damping force
115  convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
116  convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
117  // Damping force (Square Law)
118  convert["LBS/FT2/SEC2"]["N/M2/SEC2"] = 47.880259;
119  convert["N/M2/SEC2"]["LBS/FT2/SEC2"] = 1.0/convert["LBS/FT2/SEC2"]["N/M2/SEC2"];
120  // Power
121  convert["WATTS"]["HP"] = 0.001341022;
122  convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
123  // Force
124  convert["N"]["LBS"] = 0.22482;
125  convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
126  // Velocity
127  convert["KTS"]["FT/SEC"] = 1.68781;
128  convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
129  convert["M/S"]["FT/S"] = 3.2808399;
130  convert["M/SEC"]["FT/SEC"] = 3.2808399;
131  convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
132  convert["M/SEC"]["FT/SEC"] = 3.2808399;
133  convert["FT/SEC"]["M/SEC"] = 1.0/convert["M/SEC"]["FT/SEC"];
134  convert["KM/SEC"]["FT/SEC"] = 3280.8399;
135  convert["FT/SEC"]["KM/SEC"] = 1.0/convert["KM/SEC"]["FT/SEC"];
136  // Torque
137  convert["FT*LBS"]["N*M"] = 1.35581795;
138  convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
139  // Valve
140  convert["M4*SEC/KG"]["FT4*SEC/SLUG"] = convert["M"]["FT"]*convert["M"]["FT"]*
141  convert["M"]["FT"]*convert["M"]["FT"]/convert["KG"]["SLUG"];
142  convert["FT4*SEC/SLUG"]["M4*SEC/KG"] =
143  1.0/convert["M4*SEC/KG"]["FT4*SEC/SLUG"];
144  // Pressure
145  convert["INHG"]["PSF"] = 70.7180803;
146  convert["PSF"]["INHG"] = 1.0/convert["INHG"]["PSF"];
147  convert["ATM"]["INHG"] = 29.9246899;
148  convert["INHG"]["ATM"] = 1.0/convert["ATM"]["INHG"];
149  convert["PSI"]["INHG"] = 2.03625437;
150  convert["INHG"]["PSI"] = 1.0/convert["PSI"]["INHG"];
151  convert["INHG"]["PA"] = 3386.0; // inches Mercury to pascals
152  convert["PA"]["INHG"] = 1.0/convert["INHG"]["PA"];
153  convert["LBS/FT2"]["N/M2"] = 14.5939/convert["FT"]["M"];
154  convert["N/M2"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["N/M2"];
155  convert["LBS/FT2"]["PA"] = convert["LBS/FT2"]["N/M2"];
156  convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
157  // Mass flow
158  convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
159  convert ["N/SEC"]["LBS/SEC"] = 0.224808943;
160  convert ["LBS/SEC"]["N/SEC"] = 1.0/convert ["N/SEC"]["LBS/SEC"];
161  // Fuel Consumption
162  convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
163  convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
164  // Density
165  convert["KG/L"]["LBS/GAL"] = 8.3454045;
166  convert["LBS/GAL"]["KG/L"] = 1.0/convert["KG/L"]["LBS/GAL"];
167 
168  // Length
169  convert["M"]["M"] = 1.00;
170  convert["KM"]["KM"] = 1.00;
171  convert["FT"]["FT"] = 1.00;
172  convert["IN"]["IN"] = 1.00;
173  // Area
174  convert["M2"]["M2"] = 1.00;
175  convert["FT2"]["FT2"] = 1.00;
176  // Volume
177  convert["IN3"]["IN3"] = 1.00;
178  convert["CC"]["CC"] = 1.0;
179  convert["M3"]["M3"] = 1.0;
180  convert["FT3"]["FT3"] = 1.0;
181  convert["LTR"]["LTR"] = 1.0;
182  // Mass & Weight
183  convert["KG"]["KG"] = 1.00;
184  convert["LBS"]["LBS"] = 1.00;
185  // Moments of Inertia
186  convert["KG*M2"]["KG*M2"] = 1.00;
187  convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
188  // Angles
189  convert["DEG"]["DEG"] = 1.00;
190  convert["RAD"]["RAD"] = 1.00;
191  // Angular rates
192  convert["DEG/SEC"]["DEG/SEC"] = 1.00;
193  convert["RAD/SEC"]["RAD/SEC"] = 1.00;
194  // Spring force
195  convert["LBS/FT"]["LBS/FT"] = 1.00;
196  convert["N/M"]["N/M"] = 1.00;
197  // Damping force
198  convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
199  convert["N/M/SEC"]["N/M/SEC"] = 1.00;
200  // Damping force (Square law)
201  convert["LBS/FT2/SEC2"]["LBS/FT2/SEC2"] = 1.00;
202  convert["N/M2/SEC2"]["N/M2/SEC2"] = 1.00;
203  // Power
204  convert["HP"]["HP"] = 1.00;
205  convert["WATTS"]["WATTS"] = 1.00;
206  // Force
207  convert["N"]["N"] = 1.00;
208  // Velocity
209  convert["FT/SEC"]["FT/SEC"] = 1.00;
210  convert["KTS"]["KTS"] = 1.00;
211  convert["M/S"]["M/S"] = 1.0;
212  convert["M/SEC"]["M/SEC"] = 1.0;
213  convert["KM/SEC"]["KM/SEC"] = 1.0;
214  // Torque
215  convert["FT*LBS"]["FT*LBS"] = 1.00;
216  convert["N*M"]["N*M"] = 1.00;
217  // Valve
218  convert["M4*SEC/KG"]["M4*SEC/KG"] = 1.0;
219  convert["FT4*SEC/SLUG"]["FT4*SEC/SLUG"] = 1.0;
220  // Pressure
221  convert["PSI"]["PSI"] = 1.00;
222  convert["PSF"]["PSF"] = 1.00;
223  convert["INHG"]["INHG"] = 1.00;
224  convert["ATM"]["ATM"] = 1.0;
225  convert["PA"]["PA"] = 1.0;
226  convert["N/M2"]["N/M2"] = 1.00;
227  convert["LBS/FT2"]["LBS/FT2"] = 1.00;
228  // Mass flow
229  convert["LBS/SEC"]["LBS/SEC"] = 1.00;
230  convert["KG/MIN"]["KG/MIN"] = 1.0;
231  convert["LBS/MIN"]["LBS/MIN"] = 1.0;
232  convert["N/SEC"]["N/SEC"] = 1.0;
233  // Fuel Consumption
234  convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
235  convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
236  // Density
237  convert["KG/L"]["KG/L"] = 1.0;
238  convert["LBS/GAL"]["LBS/GAL"] = 1.0;
239  }
240 }
241 
242 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
243 
244 Element::~Element(void)
245 {
246  for (unsigned int i = 0; i < children.size(); ++i)
247  children[i]->SetParent(0);
248 }
249 
250 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
251 
252 string Element::GetAttributeValue(const string& attr)
253 {
254  if (HasAttribute(attr)) return attributes[attr];
255  else return ("");
256 }
257 
258 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259 
260 bool Element::SetAttributeValue(const std::string& key, const std::string& value)
261 {
262  bool ret = HasAttribute(key);
263  if (ret)
264  attributes[key] = value;
265 
266  return ret;
267 }
268 
269 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
270 
271 double Element::GetAttributeValueAsNumber(const string& attr)
272 {
273  string attribute = GetAttributeValue(attr);
274 
275  if (attribute.empty()) {
276  cerr << ReadFrom() << "Expecting numeric attribute value, but got no data"
277  << endl;
278  exit(-1);
279  }
280  else {
281  double number=0;
282  if (is_number(trim(attribute)))
283  number = atof(attribute.c_str());
284  else {
285  cerr << ReadFrom() << "Expecting numeric attribute value, but got: "
286  << attribute << endl;
287  exit(-1);
288  }
289 
290  return (number);
291  }
292 }
293 
294 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295 
296 Element* Element::GetElement(unsigned int el)
297 {
298  if (children.size() > el) {
299  element_index = el;
300  return children[el];
301  }
302  else {
303  element_index = 0;
304  return 0L;
305  }
306 }
307 
308 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
309 
310 Element* Element::GetNextElement(void)
311 {
312  if (children.size() > element_index+1) {
313  element_index++;
314  return children[element_index];
315  } else {
316  element_index = 0;
317  return 0L;
318  }
319 }
320 
321 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
322 
323 string Element::GetDataLine(unsigned int i)
324 {
325  if (data_lines.size() > 0) return data_lines[i];
326  else return string("");
327 }
328 
329 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
330 
331 double Element::GetDataAsNumber(void)
332 {
333  if (data_lines.size() == 1) {
334  double number=0;
335  if (is_number(trim(data_lines[0])))
336  number = atof(data_lines[0].c_str());
337  else {
338  cerr << ReadFrom() << "Expected numeric value, but got: " << data_lines[0]
339  << endl;
340  exit(-1);
341  }
342 
343  return number;
344  } else if (data_lines.size() == 0) {
345  cerr << ReadFrom() << "Expected numeric value, but got no data" << endl;
346  exit(-1);
347  } else {
348  cerr << ReadFrom() << "Attempting to get single data value in element "
349  << "<" << name << ">" << endl
350  << " from multiple lines:" << endl;
351  for(unsigned int i=0; i<data_lines.size(); ++i)
352  cerr << data_lines[i] << endl;
353  exit(-1);
354  }
355 }
356 
357 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358 
359 unsigned int Element::GetNumElements(const string& element_name)
360 {
361  unsigned int number_of_elements=0;
362  Element* el=FindElement(element_name);
363  while (el) {
364  number_of_elements++;
365  el=FindNextElement(element_name);
366  }
367  return number_of_elements;
368 }
369 
370 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371 
372 Element* Element::FindElement(const string& el)
373 {
374  if (el.empty() && children.size() >= 1) {
375  element_index = 1;
376  return children[0];
377  }
378  for (unsigned int i=0; i<children.size(); i++) {
379  if (el == children[i]->GetName()) {
380  element_index = i+1;
381  return children[i];
382  }
383  }
384  element_index = 0;
385  return 0L;
386 }
387 
388 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389 
390 Element* Element::FindNextElement(const string& el)
391 {
392  if (el.empty()) {
393  if (element_index < children.size()) {
394  return children[element_index++];
395  } else {
396  element_index = 0;
397  return 0L;
398  }
399  }
400  for (unsigned int i=element_index; i<children.size(); i++) {
401  if (el == children[i]->GetName()) {
402  element_index = i+1;
403  return children[i];
404  }
405  }
406  element_index = 0;
407  return 0L;
408 }
409 
410 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 
412 double Element::FindElementValueAsNumber(const string& el)
413 {
414  Element* element = FindElement(el);
415  if (element) {
416  double value = element->GetDataAsNumber();
417  value = DisperseValue(element, value);
418  return value;
419  } else {
420  cerr << ReadFrom() << "Attempting to get non-existent element " << el
421  << endl;
422  exit(-1);
423  }
424 }
425 
426 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427 
428 string Element::FindElementValue(const string& el)
429 {
430  Element* element = FindElement(el);
431  if (element) {
432  return element->GetDataLine();
433  } else {
434  return "";
435  }
436 }
437 
438 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
439 
440 double Element::FindElementValueAsNumberConvertTo(const string& el, const string& target_units)
441 {
442  Element* element = FindElement(el);
443 
444  if (!element) {
445  cerr << ReadFrom() << "Attempting to get non-existent element " << el
446  << endl;
447  exit(-1);
448  }
449 
450  string supplied_units = element->GetAttributeValue("unit");
451 
452  if (!supplied_units.empty()) {
453  if (convert.find(supplied_units) == convert.end()) {
454  cerr << element->ReadFrom() << "Supplied unit: \""
455  << supplied_units << "\" does not exist (typo?)." << endl;
456  exit(-1);
457  }
458  if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
459  cerr << element->ReadFrom() << "Supplied unit: \""
460  << supplied_units << "\" cannot be converted to " << target_units
461  << endl;
462  exit(-1);
463  }
464  }
465 
466  double value = element->GetDataAsNumber();
467 
468  // Sanity check for angular values
469  if ((supplied_units == "RAD") && (fabs(value) > 2 * M_PI)) {
470  cerr << element->ReadFrom() << element->GetName() << " value "
471  << value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
472  << endl;
473  }
474  if ((supplied_units == "DEG") && (fabs(value) > 360.0)) {
475  cerr << element->ReadFrom() << element->GetName() << " value "
476  << value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
477  << endl;
478  }
479 
480 
481  if (!supplied_units.empty()) {
482  value *= convert[supplied_units][target_units];
483  }
484 
485  if ((target_units == "RAD") && (fabs(value) > 2 * M_PI)) {
486  cerr << element->ReadFrom() << element->GetName() << " value "
487  << value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
488  << endl;
489  }
490  if ((target_units == "DEG") && (fabs(value) > 360.0)) {
491  cerr << element->ReadFrom() << element->GetName() << " value "
492  << value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
493  << endl;
494  }
495 
496  value = DisperseValue(element, value, supplied_units, target_units);
497 
498  return value;
499 }
500 
501 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
502 
503 double Element::FindElementValueAsNumberConvertFromTo( const string& el,
504  const string& supplied_units,
505  const string& target_units)
506 {
507  Element* element = FindElement(el);
508 
509  if (!element) {
510  cerr << "Attempting to get non-existent element " << el << endl;
511  exit(-1);
512  }
513 
514  if (!supplied_units.empty()) {
515  if (convert.find(supplied_units) == convert.end()) {
516  cerr << element->ReadFrom() << "Supplied unit: \""
517  << supplied_units << "\" does not exist (typo?)." << endl;
518  exit(-1);
519  }
520  if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
521  cerr << element->ReadFrom() << "Supplied unit: \""
522  << supplied_units << "\" cannot be converted to " << target_units
523  << endl;
524  exit(-1);
525  }
526  }
527 
528  double value = element->GetDataAsNumber();
529  if (!supplied_units.empty()) {
530  value *= convert[supplied_units][target_units];
531  }
532 
533  value = DisperseValue(element, value, supplied_units, target_units);
534 
535  return value;
536 }
537 
538 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539 
540 FGColumnVector3 Element::FindElementTripletConvertTo( const string& target_units)
541 {
542  FGColumnVector3 triplet;
543  Element* item;
544  double value=0.0;
545  string supplied_units = GetAttributeValue("unit");
546 
547  if (!supplied_units.empty()) {
548  if (convert.find(supplied_units) == convert.end()) {
549  cerr << ReadFrom() << "Supplied unit: \""
550  << supplied_units << "\" does not exist (typo?)." << endl;
551  exit(-1);
552  }
553  if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
554  cerr << ReadFrom() << "Supplied unit: \""
555  << supplied_units << "\" cannot be converted to " << target_units
556  << endl;
557  exit(-1);
558  }
559  }
560 
561  item = FindElement("x");
562  if (!item) item = FindElement("roll");
563  if (item) {
564  value = item->GetDataAsNumber();
565  if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
566  triplet(1) = DisperseValue(item, value, supplied_units, target_units);
567  } else {
568  triplet(1) = 0.0;
569  }
570 
571 
572  item = FindElement("y");
573  if (!item) item = FindElement("pitch");
574  if (item) {
575  value = item->GetDataAsNumber();
576  if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
577  triplet(2) = DisperseValue(item, value, supplied_units, target_units);
578  } else {
579  triplet(2) = 0.0;
580  }
581 
582  item = FindElement("z");
583  if (!item) item = FindElement("yaw");
584  if (item) {
585  value = item->GetDataAsNumber();
586  if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
587  triplet(3) = DisperseValue(item, value, supplied_units, target_units);
588  } else {
589  triplet(3) = 0.0;
590  }
591 
592  return triplet;
593 }
594 
595 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
596 
597 double Element::DisperseValue(Element *e, double val, const std::string& supplied_units,
598  const std::string& target_units)
599 {
600  double value=val;
601 
602  bool disperse = false;
603  try {
604  char* num = getenv("JSBSIM_DISPERSE");
605  if (num) {
606  disperse = (atoi(num) == 1); // set dispersions
607  }
608  } catch (...) { // if error set to false
609  disperse = false;
610  std::cerr << "Could not process JSBSIM_DISPERSE environment variable: Assumed NO dispersions." << endl;
611  }
612 
613  if (e->HasAttribute("dispersion") && disperse) {
614  double disp = e->GetAttributeValueAsNumber("dispersion");
615  if (!supplied_units.empty()) disp *= convert[supplied_units][target_units];
616  string attType = e->GetAttributeValue("type");
617  if (attType == "gaussian" || attType == "gaussiansigned") {
618  double grn = FGJSBBase::GaussianRandomNumber();
619  if (attType == "gaussian") {
620  value = val + disp*grn;
621  } else { // Assume gaussiansigned
622  value = (val + disp*grn)*(fabs(grn)/grn);
623  }
624  } else if (attType == "uniform" || attType == "uniformsigned") {
625  double urn = ((((double)rand()/RAND_MAX)-0.5)*2.0);
626  if (attType == "uniform") {
627  value = val + disp * urn;
628  } else { // Assume uniformsigned
629  value = (val + disp * urn)*(fabs(urn)/urn);
630  }
631  } else {
632  cerr << ReadFrom() << "Unknown dispersion type" << attType << endl;
633  exit(-1);
634  }
635 
636  }
637  return value;
638 }
639 
640 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
641 
642 void Element::Print(unsigned int level)
643 {
644  unsigned int i, spaces;
645 
646  level+=2;
647  for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
648  cout << "Element Name: " << name;
649 
650  map<string, string>::iterator it;
651  for (it = attributes.begin(); it != attributes.end(); ++it)
652  cout << " " << it->first << " = " << it->second;
653 
654  cout << endl;
655  for (i=0; i<data_lines.size(); i++) {
656  for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
657  cout << data_lines[i] << endl;
658  }
659  for (i=0; i<children.size(); i++) {
660  children[i]->Print(level);
661  }
662 }
663 
664 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
665 
666 void Element::AddAttribute(const string& name, const string& value)
667 {
668  attributes[name] = value;
669 }
670 
671 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
672 
673 void Element::AddData(string d)
674 {
675  string::size_type string_start = d.find_first_not_of(" \t");
676  if (string_start != string::npos && string_start > 0) {
677  d.erase(0,string_start);
678  }
679  data_lines.push_back(d);
680 }
681 
682 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
683 
684 string Element::ReadFrom(void) const
685 {
686  ostringstream message;
687 
688  message << endl
689  << "In file " << GetFileName() << ": line " << GetLineNumber()
690  << endl;
691 
692  return message.str();
693 }
694 
695 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
696 
697 void Element::MergeAttributes(Element* el)
698 {
699  map<string, string>::iterator it;
700 
701  for (it=el->attributes.begin(); it != el->attributes.end(); ++it) {
702  if (attributes.find(it->first) == attributes.end())
703  attributes[it->first] = it->second;
704  else {
705  if (FGJSBBase::debug_lvl > 0 && (attributes[it->first] != it->second))
706  cout << el->ReadFrom() << " Attribute '" << it->first << "' is overridden in file "
707  << GetFileName() << ": line " << GetLineNumber() << endl
708  << " The value '" << attributes[it->first] << "' will be used instead of '"
709  << it->second << "'." << endl;
710  }
711  }
712 }
713 
714 } // end namespace JSBSim
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
Definition: FGXMLElement.h:162
STL namespace.
double GetDataAsNumber(void)
Converts the element data to a number.
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.
This class implements a 3 element column vector.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...