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