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