34 #include "FGXMLElement.h"
35 #include "FGJSBBase.h"
45 bool Element::converterIsInitialized =
false;
46 map <string, map <string, double> > Element::convert;
52 Element::Element(
const string& nm)
59 if (!converterIsInitialized) {
60 converterIsInitialized =
true;
63 convert[
"M"][
"FT"] = 3.2808399;
64 convert[
"FT"][
"M"] = 1.0/convert[
"M"][
"FT"];
65 convert[
"CM"][
"FT"] = 0.032808399;
66 convert[
"FT"][
"CM"] = 1.0/convert[
"CM"][
"FT"];
67 convert[
"KM"][
"FT"] = 3280.8399;
68 convert[
"FT"][
"KM"] = 1.0/convert[
"KM"][
"FT"];
69 convert[
"FT"][
"IN"] = 12.0;
70 convert[
"IN"][
"FT"] = 1.0/convert[
"FT"][
"IN"];
71 convert[
"IN"][
"M"] = convert[
"IN"][
"FT"] * convert[
"FT"][
"M"];
72 convert[
"M"][
"IN"] = convert[
"M"][
"FT"] * convert[
"FT"][
"IN"];
74 convert[
"M2"][
"FT2"] = convert[
"M"][
"FT"]*convert[
"M"][
"FT"];
75 convert[
"FT2"][
"M2"] = 1.0/convert[
"M2"][
"FT2"];
76 convert[
"CM2"][
"FT2"] = convert[
"CM"][
"FT"]*convert[
"CM"][
"FT"];
77 convert[
"FT2"][
"CM2"] = 1.0/convert[
"CM2"][
"FT2"];
78 convert[
"M2"][
"IN2"] = convert[
"M"][
"IN"]*convert[
"M"][
"IN"];
79 convert[
"IN2"][
"M2"] = 1.0/convert[
"M2"][
"IN2"];
80 convert[
"FT2"][
"IN2"] = 144.0;
81 convert[
"IN2"][
"FT2"] = 1.0/convert[
"FT2"][
"IN2"];
83 convert[
"IN3"][
"CC"] = 16.387064;
84 convert[
"CC"][
"IN3"] = 1.0/convert[
"IN3"][
"CC"];
85 convert[
"FT3"][
"IN3"] = 1728.0;
86 convert[
"IN3"][
"FT3"] = 1.0/convert[
"FT3"][
"IN3"];
87 convert[
"M3"][
"FT3"] = 35.3146667;
88 convert[
"FT3"][
"M3"] = 1.0/convert[
"M3"][
"FT3"];
89 convert[
"LTR"][
"IN3"] = 61.0237441;
90 convert[
"IN3"][
"LTR"] = 1.0/convert[
"LTR"][
"IN3"];
91 convert[
"GAL"][
"FT3"] = 0.133681;
92 convert[
"FT3"][
"GAL"] = 1.0/convert[
"GAL"][
"FT3"];
93 convert[
"IN3"][
"GAL"] = convert[
"IN3"][
"FT3"]*convert[
"FT3"][
"GAL"];
94 convert[
"LTR"][
"GAL"] = convert[
"LTR"][
"IN3"]*convert[
"IN3"][
"GAL"];
95 convert[
"M3"][
"GAL"] = 1000.*convert[
"LTR"][
"GAL"];
96 convert[
"CC"][
"GAL"] = convert[
"CC"][
"IN3"]*convert[
"IN3"][
"GAL"];
98 convert[
"LBS"][
"KG"] = 0.45359237;
99 convert[
"KG"][
"LBS"] = 1.0/convert[
"LBS"][
"KG"];
100 convert[
"SLUG"][
"KG"] = 14.59390;
101 convert[
"KG"][
"SLUG"] = 1.0/convert[
"SLUG"][
"KG"];
103 convert[
"SLUG*FT2"][
"KG*M2"] = 1.35594;
104 convert[
"KG*M2"][
"SLUG*FT2"] = 1.0/convert[
"SLUG*FT2"][
"KG*M2"];
106 convert[
"RAD"][
"DEG"] = 180.0/M_PI;
107 convert[
"DEG"][
"RAD"] = 1.0/convert[
"RAD"][
"DEG"];
109 convert[
"RAD/SEC"][
"DEG/SEC"] = convert[
"RAD"][
"DEG"];
110 convert[
"DEG/SEC"][
"RAD/SEC"] = 1.0/convert[
"RAD/SEC"][
"DEG/SEC"];
112 convert[
"LBS/FT"][
"N/M"] = 14.5939;
113 convert[
"N/M"][
"LBS/FT"] = 1.0/convert[
"LBS/FT"][
"N/M"];
115 convert[
"LBS/FT/SEC"][
"N/M/SEC"] = 14.5939;
116 convert[
"N/M/SEC"][
"LBS/FT/SEC"] = 1.0/convert[
"LBS/FT/SEC"][
"N/M/SEC"];
118 convert[
"LBS/FT2/SEC2"][
"N/M2/SEC2"] = 47.880259;
119 convert[
"N/M2/SEC2"][
"LBS/FT2/SEC2"] = 1.0/convert[
"LBS/FT2/SEC2"][
"N/M2/SEC2"];
121 convert[
"WATTS"][
"HP"] = 0.001341022;
122 convert[
"HP"][
"WATTS"] = 1.0/convert[
"WATTS"][
"HP"];
124 convert[
"N"][
"LBS"] = 0.22482;
125 convert[
"LBS"][
"N"] = 1.0/convert[
"N"][
"LBS"];
127 convert[
"KTS"][
"FT/SEC"] = 1.6878098571;
128 convert[
"FT/SEC"][
"KTS"] = 1.0/convert[
"KTS"][
"FT/SEC"];
129 convert[
"M/S"][
"FT/S"] = 3.2808399;
130 convert[
"M/S"][
"KTS"] = convert[
"M/S"][
"FT/S"]/convert[
"KTS"][
"FT/SEC"];
131 convert[
"M/SEC"][
"FT/SEC"] = 3.2808399;
132 convert[
"FT/S"][
"M/S"] = 1.0/convert[
"M/S"][
"FT/S"];
133 convert[
"M/SEC"][
"FT/SEC"] = 3.2808399;
134 convert[
"FT/SEC"][
"M/SEC"] = 1.0/convert[
"M/SEC"][
"FT/SEC"];
135 convert[
"KM/SEC"][
"FT/SEC"] = 3280.8399;
136 convert[
"FT/SEC"][
"KM/SEC"] = 1.0/convert[
"KM/SEC"][
"FT/SEC"];
138 convert[
"FT*LBS"][
"N*M"] = 1.35581795;
139 convert[
"N*M"][
"FT*LBS"] = 1/convert[
"FT*LBS"][
"N*M"];
141 convert[
"M4*SEC/KG"][
"FT4*SEC/SLUG"] = convert[
"M"][
"FT"]*convert[
"M"][
"FT"]*
142 convert[
"M"][
"FT"]*convert[
"M"][
"FT"]/convert[
"KG"][
"SLUG"];
143 convert[
"FT4*SEC/SLUG"][
"M4*SEC/KG"] =
144 1.0/convert[
"M4*SEC/KG"][
"FT4*SEC/SLUG"];
146 convert[
"INHG"][
"PSF"] = 70.7180803;
147 convert[
"PSF"][
"INHG"] = 1.0/convert[
"INHG"][
"PSF"];
148 convert[
"ATM"][
"INHG"] = 29.9246899;
149 convert[
"INHG"][
"ATM"] = 1.0/convert[
"ATM"][
"INHG"];
150 convert[
"PSI"][
"INHG"] = 2.03625437;
151 convert[
"INHG"][
"PSI"] = 1.0/convert[
"PSI"][
"INHG"];
152 convert[
"INHG"][
"PA"] = 3386.0;
153 convert[
"PA"][
"INHG"] = 1.0/convert[
"INHG"][
"PA"];
154 convert[
"LBS/FT2"][
"N/M2"] = 14.5939/convert[
"FT"][
"M"];
155 convert[
"N/M2"][
"LBS/FT2"] = 1.0/convert[
"LBS/FT2"][
"N/M2"];
156 convert[
"LBS/FT2"][
"PA"] = convert[
"LBS/FT2"][
"N/M2"];
157 convert[
"PA"][
"LBS/FT2"] = 1.0/convert[
"LBS/FT2"][
"PA"];
159 convert[
"KG/MIN"][
"LBS/MIN"] = convert[
"KG"][
"LBS"];
160 convert[
"KG/SEC"][
"LBS/SEC"] = convert[
"KG"][
"LBS"];
161 convert [
"N/SEC"][
"LBS/SEC"] = 0.224808943;
162 convert [
"LBS/SEC"][
"N/SEC"] = 1.0/convert [
"N/SEC"][
"LBS/SEC"];
164 convert[
"LBS/HP*HR"][
"KG/KW*HR"] = 0.6083;
165 convert[
"KG/KW*HR"][
"LBS/HP*HR"] = 1.0/convert[
"LBS/HP*HR"][
"KG/KW*HR"];
167 convert[
"KG/L"][
"LBS/GAL"] = 8.3454045;
168 convert[
"LBS/GAL"][
"KG/L"] = 1.0/convert[
"KG/L"][
"LBS/GAL"];
170 convert[
"FT3/SEC2"][
"M3/SEC2"] = convert[
"FT3"][
"M3"];
171 convert[
"M3/SEC2"][
"FT3/SEC2"] = convert[
"M3"][
"FT3"];
174 convert[
"M"][
"M"] = 1.00;
175 convert[
"KM"][
"KM"] = 1.00;
176 convert[
"FT"][
"FT"] = 1.00;
177 convert[
"IN"][
"IN"] = 1.00;
179 convert[
"M2"][
"M2"] = 1.00;
180 convert[
"FT2"][
"FT2"] = 1.00;
182 convert[
"IN3"][
"IN3"] = 1.00;
183 convert[
"CC"][
"CC"] = 1.0;
184 convert[
"M3"][
"M3"] = 1.0;
185 convert[
"FT3"][
"FT3"] = 1.0;
186 convert[
"LTR"][
"LTR"] = 1.0;
187 convert[
"GAL"][
"GAL"] = 1.0;
189 convert[
"KG"][
"KG"] = 1.00;
190 convert[
"LBS"][
"LBS"] = 1.00;
192 convert[
"KG*M2"][
"KG*M2"] = 1.00;
193 convert[
"SLUG*FT2"][
"SLUG*FT2"] = 1.00;
195 convert[
"DEG"][
"DEG"] = 1.00;
196 convert[
"RAD"][
"RAD"] = 1.00;
198 convert[
"DEG/SEC"][
"DEG/SEC"] = 1.00;
199 convert[
"RAD/SEC"][
"RAD/SEC"] = 1.00;
201 convert[
"LBS/FT"][
"LBS/FT"] = 1.00;
202 convert[
"N/M"][
"N/M"] = 1.00;
204 convert[
"LBS/FT/SEC"][
"LBS/FT/SEC"] = 1.00;
205 convert[
"N/M/SEC"][
"N/M/SEC"] = 1.00;
207 convert[
"LBS/FT2/SEC2"][
"LBS/FT2/SEC2"] = 1.00;
208 convert[
"N/M2/SEC2"][
"N/M2/SEC2"] = 1.00;
210 convert[
"HP"][
"HP"] = 1.00;
211 convert[
"WATTS"][
"WATTS"] = 1.00;
213 convert[
"N"][
"N"] = 1.00;
215 convert[
"FT/SEC"][
"FT/SEC"] = 1.00;
216 convert[
"KTS"][
"KTS"] = 1.00;
217 convert[
"M/S"][
"M/S"] = 1.0;
218 convert[
"M/SEC"][
"M/SEC"] = 1.0;
219 convert[
"KM/SEC"][
"KM/SEC"] = 1.0;
221 convert[
"FT*LBS"][
"FT*LBS"] = 1.00;
222 convert[
"N*M"][
"N*M"] = 1.00;
224 convert[
"M4*SEC/KG"][
"M4*SEC/KG"] = 1.0;
225 convert[
"FT4*SEC/SLUG"][
"FT4*SEC/SLUG"] = 1.0;
227 convert[
"PSI"][
"PSI"] = 1.00;
228 convert[
"PSF"][
"PSF"] = 1.00;
229 convert[
"INHG"][
"INHG"] = 1.00;
230 convert[
"ATM"][
"ATM"] = 1.0;
231 convert[
"PA"][
"PA"] = 1.0;
232 convert[
"N/M2"][
"N/M2"] = 1.00;
233 convert[
"LBS/FT2"][
"LBS/FT2"] = 1.00;
235 convert[
"LBS/SEC"][
"LBS/SEC"] = 1.00;
236 convert[
"KG/MIN"][
"KG/MIN"] = 1.0;
237 convert[
"LBS/MIN"][
"LBS/MIN"] = 1.0;
238 convert[
"N/SEC"][
"N/SEC"] = 1.0;
240 convert[
"LBS/HP*HR"][
"LBS/HP*HR"] = 1.0;
241 convert[
"KG/KW*HR"][
"KG/KW*HR"] = 1.0;
243 convert[
"KG/L"][
"KG/L"] = 1.0;
244 convert[
"LBS/GAL"][
"LBS/GAL"] = 1.0;
246 convert[
"FT3/SEC2"][
"FT3/SEC2"] = 1.0;
247 convert[
"M3/SEC2"][
"M3/SEC2"] = 1.0;
249 convert[
"VOLTS"][
"VOLTS"] = 1.0;
250 convert[
"OHMS"][
"OHMS"] = 1.0;
251 convert[
"AMPERES"][
"AMPERES"] = 1.0;
257 Element::~Element(
void)
259 for (
unsigned int i = 0; i < children.size(); ++i)
260 children[i]->SetParent(0);
265 string Element::GetAttributeValue(
const string& attr)
267 if (HasAttribute(attr))
return attributes[attr];
273 bool Element::SetAttributeValue(
const std::string& key,
const std::string& value)
275 bool ret = HasAttribute(key);
277 attributes[key] = value;
284 double Element::GetAttributeValueAsNumber(
const string& attr)
286 string attribute = GetAttributeValue(attr);
288 if (attribute.empty()) {
290 s << ReadFrom() <<
"Expecting numeric attribute value, but got no data";
291 cerr << s.str() << endl;
292 throw length_error(s.str());
296 if (is_number(trim(attribute)))
297 number = atof_locale_c(attribute);
300 s << ReadFrom() <<
"Expecting numeric attribute value, but got: " << attribute;
301 cerr << s.str() << endl;
313 if (children.size() > el) {
327 if (children.size() > element_index+1) {
329 return children[element_index];
338 string Element::GetDataLine(
unsigned int i)
340 if (!data_lines.empty())
return data_lines[i];
341 else return string(
"");
346 double Element::GetDataAsNumber(
void)
348 if (data_lines.size() == 1) {
350 if (is_number(trim(data_lines[0])))
351 number = atof_locale_c(data_lines[0]);
354 s << ReadFrom() <<
"Expected numeric value, but got: " << data_lines[0];
355 cerr << s.str() << endl;
360 }
else if (data_lines.empty()) {
362 s << ReadFrom() <<
"Expected numeric value, but got no data";
363 cerr << s.str() << endl;
364 throw length_error(s.str());
366 cerr << ReadFrom() <<
"Attempting to get single data value in element "
367 <<
"<" << name <<
">" << endl
368 <<
" from multiple lines:" << endl;
369 for(
unsigned int i=0; i<data_lines.size(); ++i)
370 cerr << data_lines[i] << endl;
372 s << ReadFrom() <<
"Attempting to get single data value in element "
373 <<
"<" << name <<
">"
374 <<
" from multiple lines (" << data_lines.size() <<
").";
375 throw length_error(s.str());
381 unsigned int Element::GetNumElements(
const string& element_name)
383 unsigned int number_of_elements=0;
384 Element* el=FindElement(element_name);
386 number_of_elements++;
387 el=FindNextElement(element_name);
389 return number_of_elements;
394 Element* Element::FindElement(
const string& el)
396 if (el.empty() && children.size() >= 1) {
400 for (
unsigned int i=0; i<children.size(); i++) {
401 if (el == children[i]->GetName()) {
412 Element* Element::FindNextElement(
const string& el)
415 if (element_index < children.size()) {
416 return children[element_index++];
422 for (
unsigned int i=element_index; i<children.size(); i++) {
423 if (el == children[i]->GetName()) {
434 double Element::FindElementValueAsNumber(
const string& el)
436 Element* element = FindElement(el);
439 value = DisperseValue(element, value);
443 s << ReadFrom() <<
"Attempting to get non-existent element " << el;
444 cerr << s.str() << endl;
445 throw length_error(s.str());
451 bool Element::FindElementValueAsBoolean(
const string& el)
453 Element* element = FindElement(el);
465 cerr << ReadFrom() <<
"Attempting to get non-existent element " << el <<
" ;returning false"
473 string Element::FindElementValue(
const string& el)
475 Element* element = FindElement(el);
485 double Element::FindElementValueAsNumberConvertTo(
const string& el,
const string& target_units)
487 Element* element = FindElement(el);
491 s << ReadFrom() <<
"Attempting to get non-existent element " << el;
492 cerr << s.str() << endl;
493 throw length_error(s.str());
498 if (!supplied_units.empty()) {
499 if (convert.find(supplied_units) == convert.end()) {
501 s << element->
ReadFrom() <<
"Supplied unit: \"" << supplied_units
502 <<
"\" does not exist (typo?).";
503 cerr << s.str() << endl;
504 throw invalid_argument(s.str());
506 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
508 s << element->
ReadFrom() <<
"Supplied unit: \"" << supplied_units
509 <<
"\" cannot be converted to " << target_units;
510 cerr << s.str() << endl;
511 throw invalid_argument(s.str());
518 if ((supplied_units ==
"RAD") && (fabs(value) > 2 * M_PI)) {
520 << value <<
" RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
523 if ((supplied_units ==
"DEG") && (fabs(value) > 360.0)) {
525 << value <<
" DEG is outside the range [ -360 DEG ; +360 DEG ]"
530 if (!supplied_units.empty()) {
531 value *= convert[supplied_units][target_units];
534 if ((target_units ==
"RAD") && (fabs(value) > 2 * M_PI)) {
536 << value <<
" RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
539 if ((target_units ==
"DEG") && (fabs(value) > 360.0)) {
541 << value <<
" DEG is outside the range [ -360 DEG ; +360 DEG ]"
545 value = DisperseValue(element, value, supplied_units, target_units);
552 double Element::FindElementValueAsNumberConvertFromTo(
const string& el,
553 const string& supplied_units,
554 const string& target_units)
556 Element* element = FindElement(el);
560 s << ReadFrom() <<
"Attempting to get non-existent element " << el;
561 cerr << s.str() << endl;
562 throw length_error(s.str());
565 if (!supplied_units.empty()) {
566 if (convert.find(supplied_units) == convert.end()) {
568 s << element->
ReadFrom() <<
"Supplied unit: \"" << supplied_units
569 <<
"\" does not exist (typo?).";
570 cerr << s.str() << endl;
571 throw invalid_argument(s.str());
573 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
575 s << element->
ReadFrom() <<
"Supplied unit: \"" << supplied_units
576 <<
"\" cannot be converted to " << target_units;
577 cerr << s.str() << endl;
578 throw invalid_argument(s.str());
583 if (!supplied_units.empty()) {
584 value *= convert[supplied_units][target_units];
587 value = DisperseValue(element, value, supplied_units, target_units);
599 string supplied_units = GetAttributeValue(
"unit");
601 if (!supplied_units.empty()) {
602 if (convert.find(supplied_units) == convert.end()) {
604 s << ReadFrom() <<
"Supplied unit: \"" << supplied_units
605 <<
"\" does not exist (typo?).";
606 cerr << s.str() << endl;
607 throw invalid_argument(s.str());
609 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
611 s << ReadFrom() <<
"Supplied unit: \"" << supplied_units
612 <<
"\" cannot be converted to " << target_units;
613 cerr << s.str() << endl;
614 throw invalid_argument(s.str());
618 item = FindElement(
"x");
619 if (!item) item = FindElement(
"roll");
622 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
623 triplet(1) = DisperseValue(item, value, supplied_units, target_units);
629 item = FindElement(
"y");
630 if (!item) item = FindElement(
"pitch");
633 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
634 triplet(2) = DisperseValue(item, value, supplied_units, target_units);
639 item = FindElement(
"z");
640 if (!item) item = FindElement(
"yaw");
643 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
644 triplet(3) = DisperseValue(item, value, supplied_units, target_units);
654 double Element::DisperseValue(
Element *e,
double val,
const std::string& supplied_units,
655 const std::string& target_units)
659 bool disperse =
false;
661 char* num = getenv(
"JSBSIM_DISPERSE");
663 disperse = (atoi(num) == 1);
667 std::cerr <<
"Could not process JSBSIM_DISPERSE environment variable: Assumed NO dispersions." << endl;
672 if (!supplied_units.empty()) disp *= convert[supplied_units][target_units];
674 RandomNumberGenerator generator;
676 if (attType ==
"gaussian" || attType ==
"gaussiansigned") {
677 double grn = generator.GetNormalRandomNumber();
678 if (attType ==
"gaussian")
679 value = val + disp*grn;
681 value = (val + disp*grn)*FGJSBBase::sign(grn);
682 }
else if (attType ==
"uniform" || attType ==
"uniformsigned") {
683 double urn = generator.GetUniformRandomNumber();
684 if (attType ==
"uniform")
685 value = val + disp * urn;
687 value = (val + disp * urn)*FGJSBBase::sign(urn);
690 s << ReadFrom() <<
"Unknown dispersion type" << attType;
691 cerr << s.str() << endl;
692 throw domain_error(s.str());
701 void Element::Print(
unsigned int level)
703 unsigned int i, spaces;
706 for (spaces=0; spaces<=level; spaces++) cout <<
" ";
707 cout <<
"Element Name: " << name;
709 map<string, string>::iterator it;
710 for (it = attributes.begin(); it != attributes.end(); ++it)
711 cout <<
" " << it->first <<
" = " << it->second;
714 for (i=0; i<data_lines.size(); i++) {
715 for (spaces=0; spaces<=level; spaces++) cout <<
" ";
716 cout << data_lines[i] << endl;
718 for (i=0; i<children.size(); i++) {
719 children[i]->Print(level);
725 void Element::AddAttribute(
const string& name,
const string& value)
727 attributes[name] = value;
732 void Element::AddData(
string d)
734 string::size_type string_start = d.find_first_not_of(
" \t");
735 if (string_start != string::npos && string_start > 0) {
736 d.erase(0,string_start);
738 data_lines.push_back(d);
743 string Element::ReadFrom(
void)
const
745 ostringstream message;
748 <<
"In file " << GetFileName() <<
": line " << GetLineNumber()
751 return message.str();
758 map<string, string>::iterator it;
760 for (it=el->attributes.begin(); it != el->attributes.end(); ++it) {
761 if (attributes.find(it->first) == attributes.end())
762 attributes[it->first] = it->second;
764 if (FGJSBBase::debug_lvl > 0 && (attributes[it->first] != it->second))
765 cout << el->
ReadFrom() <<
" Attribute '" << it->first <<
"' is overridden in file "
766 << GetFileName() <<
": line " << GetLineNumber() << endl
767 <<
" The value '" << attributes[it->first] <<
"' will be used instead of '"
768 << it->second <<
"'." << endl;
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to an element.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
double GetDataAsNumber(void)
Converts the element data to a number.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
const std::string & GetName(void) const
Retrieves the element name.
This class implements a 3 element column vector.