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