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