FlightGear next
FGXMLElement.cpp
Go to the documentation of this file.
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 <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
36using namespace std;
37
38/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39FORWARD DECLARATIONS
40%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
41
42namespace JSBSim {
43
44bool Element::converterIsInitialized = false;
45map <string, map <string, double> > Element::convert;
46
47/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
48CLASS IMPLEMENTATION
49%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
50
51Element::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
253{
254 for (unsigned int i = 0; i < children.size(); ++i)
255 children[i]->SetParent(0);
256}
257
258//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259
260string Element::GetAttributeValue(const string& attr)
261{
262 if (HasAttribute(attr)) return attributes[attr];
263 else return ("");
264}
265
266//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
267
268bool 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
279double 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
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
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
333string Element::GetDataLine(unsigned int i)
334{
335 if (data_lines.size() > 0) return data_lines[i];
336 else return string("");
337}
338
339//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340
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
376unsigned 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
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
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
429double 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
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
468string 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
480double 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
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
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
649double 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
696void 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
720void Element::AddAttribute(const string& name, const string& value)
721{
722 attributes[name] = value;
723}
724
725//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
726
727void 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
738string 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
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
#define M_PI
Definition FGJSBBase.h:50
#define i(x)
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.
const std::string & GetName(void) const
Retrieves the element name.
void AddAttribute(const std::string &name, const std::string &value)
Stores an attribute belonging to this element.
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
FGColumnVector3 FindElementTripletConvertTo(const std::string &target_units)
Composes a 3-element column vector for the supplied location or orientation.
void SetParent(Element *p)
This function sets the value of the parent class attribute to the supplied Element pointer.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
void Print(unsigned int level=0)
Prints the element.
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 GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
bool FindElementValueAsBoolean(const std::string &el="")
Searches for the named element and returns the data belonging to it as a bool.
std::string FindElementValue(const std::string &el="")
Searches for the named element and returns the string data belonging to it.
int GetLineNumber(void) const
Returns the line number at which the element has been defined.
~Element(void)
Destructor.
Element(const std::string &nm)
Constructor.
void AddData(std::string d)
Stores data belonging to this element.
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to an element.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
unsigned int GetNumElements(void)
Returns the number of child elements for this element.
Element * GetElement(unsigned int el=0)
Returns a pointer to the element requested by index.
bool SetAttributeValue(const std::string &key, const std::string &value)
Modifies an attribute.
double GetDataAsNumber(void)
Converts the element data to a number.
double DisperseValue(Element *e, double val, const std::string &supplied_units="", const std::string &target_units="")
void MergeAttributes(Element *el)
Merges the attributes of the current element with another element.
Element * FindElement(const std::string &el="")
Searches for a specified element.
const std::string & GetFileName(void) const
Returns the name of the file in which the element has been read.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
This class implements a 3 element column vector.
static double GaussianRandomNumber(void)
static short debug_lvl
Definition FGJSBBase.h:190
static double atof(const string &str)
Definition options.cxx:107
static int atoi(const string &str)
Definition options.cxx:113
bool is_number(const std::string &str)
std::string & trim(std::string &str)