36 #include "FGXMLElement.h" 37 #include "string_utilities.h" 38 #include "FGJSBBase.h" 48 IDENT(IdSrc,
"$Id: FGXMLElement.cpp,v 1.56 2016/09/11 11:26:04 bcoconni Exp $");
49 IDENT(IdHdr,ID_XMLELEMENT);
51 bool Element::converterIsInitialized =
false;
52 map <string, map <string, double> > Element::convert;
58 Element::Element(
const string& nm)
65 if (!converterIsInitialized) {
66 converterIsInitialized =
true;
69 convert[
"M"][
"FT"] = 3.2808399;
70 convert[
"FT"][
"M"] = 1.0/convert[
"M"][
"FT"];
71 convert[
"CM"][
"FT"] = 0.032808399;
72 convert[
"FT"][
"CM"] = 1.0/convert[
"CM"][
"FT"];
73 convert[
"KM"][
"FT"] = 3280.8399;
74 convert[
"FT"][
"KM"] = 1.0/convert[
"KM"][
"FT"];
75 convert[
"FT"][
"IN"] = 12.0;
76 convert[
"IN"][
"FT"] = 1.0/convert[
"FT"][
"IN"];
77 convert[
"IN"][
"M"] = convert[
"IN"][
"FT"] * convert[
"FT"][
"M"];
78 convert[
"M"][
"IN"] = convert[
"M"][
"FT"] * convert[
"FT"][
"IN"];
80 convert[
"M2"][
"FT2"] = convert[
"M"][
"FT"]*convert[
"M"][
"FT"];
81 convert[
"FT2"][
"M2"] = 1.0/convert[
"M2"][
"FT2"];
82 convert[
"CM2"][
"FT2"] = convert[
"CM"][
"FT"]*convert[
"CM"][
"FT"];
83 convert[
"FT2"][
"CM2"] = 1.0/convert[
"CM2"][
"FT2"];
84 convert[
"M2"][
"IN2"] = convert[
"M"][
"IN"]*convert[
"M"][
"IN"];
85 convert[
"IN2"][
"M2"] = 1.0/convert[
"M2"][
"IN2"];
86 convert[
"FT2"][
"IN2"] = 144.0;
87 convert[
"IN2"][
"FT2"] = 1.0/convert[
"FT2"][
"IN2"];
89 convert[
"IN3"][
"CC"] = 16.387064;
90 convert[
"CC"][
"IN3"] = 1.0/convert[
"IN3"][
"CC"];
91 convert[
"FT3"][
"IN3"] = 1728.0;
92 convert[
"IN3"][
"FT3"] = 1.0/convert[
"FT3"][
"IN3"];
93 convert[
"M3"][
"FT3"] = 35.3146667;
94 convert[
"FT3"][
"M3"] = 1.0/convert[
"M3"][
"FT3"];
95 convert[
"LTR"][
"IN3"] = 61.0237441;
96 convert[
"IN3"][
"LTR"] = 1.0/convert[
"LTR"][
"IN3"];
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.68781;
128 convert[
"FT/SEC"][
"KTS"] = 1.0/convert[
"KTS"][
"FT/SEC"];
129 convert[
"M/S"][
"FT/S"] = 3.2808399;
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"];
137 convert[
"FT*LBS"][
"N*M"] = 1.35581795;
138 convert[
"N*M"][
"FT*LBS"] = 1/convert[
"FT*LBS"][
"N*M"];
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"];
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;
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"];
158 convert[
"KG/MIN"][
"LBS/MIN"] = convert[
"KG"][
"LBS"];
159 convert [
"N/SEC"][
"LBS/SEC"] = 0.224808943;
160 convert [
"LBS/SEC"][
"N/SEC"] = 1.0/convert [
"N/SEC"][
"LBS/SEC"];
162 convert[
"LBS/HP*HR"][
"KG/KW*HR"] = 0.6083;
163 convert[
"KG/KW*HR"][
"LBS/HP*HR"] = 1.0/convert[
"LBS/HP*HR"][
"KG/KW*HR"];
165 convert[
"KG/L"][
"LBS/GAL"] = 8.3454045;
166 convert[
"LBS/GAL"][
"KG/L"] = 1.0/convert[
"KG/L"][
"LBS/GAL"];
169 convert[
"M"][
"M"] = 1.00;
170 convert[
"KM"][
"KM"] = 1.00;
171 convert[
"FT"][
"FT"] = 1.00;
172 convert[
"IN"][
"IN"] = 1.00;
174 convert[
"M2"][
"M2"] = 1.00;
175 convert[
"FT2"][
"FT2"] = 1.00;
177 convert[
"IN3"][
"IN3"] = 1.00;
178 convert[
"CC"][
"CC"] = 1.0;
179 convert[
"M3"][
"M3"] = 1.0;
180 convert[
"FT3"][
"FT3"] = 1.0;
181 convert[
"LTR"][
"LTR"] = 1.0;
183 convert[
"KG"][
"KG"] = 1.00;
184 convert[
"LBS"][
"LBS"] = 1.00;
186 convert[
"KG*M2"][
"KG*M2"] = 1.00;
187 convert[
"SLUG*FT2"][
"SLUG*FT2"] = 1.00;
189 convert[
"DEG"][
"DEG"] = 1.00;
190 convert[
"RAD"][
"RAD"] = 1.00;
192 convert[
"DEG/SEC"][
"DEG/SEC"] = 1.00;
193 convert[
"RAD/SEC"][
"RAD/SEC"] = 1.00;
195 convert[
"LBS/FT"][
"LBS/FT"] = 1.00;
196 convert[
"N/M"][
"N/M"] = 1.00;
198 convert[
"LBS/FT/SEC"][
"LBS/FT/SEC"] = 1.00;
199 convert[
"N/M/SEC"][
"N/M/SEC"] = 1.00;
201 convert[
"LBS/FT2/SEC2"][
"LBS/FT2/SEC2"] = 1.00;
202 convert[
"N/M2/SEC2"][
"N/M2/SEC2"] = 1.00;
204 convert[
"HP"][
"HP"] = 1.00;
205 convert[
"WATTS"][
"WATTS"] = 1.00;
207 convert[
"N"][
"N"] = 1.00;
209 convert[
"FT/SEC"][
"FT/SEC"] = 1.00;
210 convert[
"KTS"][
"KTS"] = 1.00;
211 convert[
"M/S"][
"M/S"] = 1.0;
212 convert[
"M/SEC"][
"M/SEC"] = 1.0;
213 convert[
"KM/SEC"][
"KM/SEC"] = 1.0;
215 convert[
"FT*LBS"][
"FT*LBS"] = 1.00;
216 convert[
"N*M"][
"N*M"] = 1.00;
218 convert[
"M4*SEC/KG"][
"M4*SEC/KG"] = 1.0;
219 convert[
"FT4*SEC/SLUG"][
"FT4*SEC/SLUG"] = 1.0;
221 convert[
"PSI"][
"PSI"] = 1.00;
222 convert[
"PSF"][
"PSF"] = 1.00;
223 convert[
"INHG"][
"INHG"] = 1.00;
224 convert[
"ATM"][
"ATM"] = 1.0;
225 convert[
"PA"][
"PA"] = 1.0;
226 convert[
"N/M2"][
"N/M2"] = 1.00;
227 convert[
"LBS/FT2"][
"LBS/FT2"] = 1.00;
229 convert[
"LBS/SEC"][
"LBS/SEC"] = 1.00;
230 convert[
"KG/MIN"][
"KG/MIN"] = 1.0;
231 convert[
"LBS/MIN"][
"LBS/MIN"] = 1.0;
232 convert[
"N/SEC"][
"N/SEC"] = 1.0;
234 convert[
"LBS/HP*HR"][
"LBS/HP*HR"] = 1.0;
235 convert[
"KG/KW*HR"][
"KG/KW*HR"] = 1.0;
237 convert[
"KG/L"][
"KG/L"] = 1.0;
238 convert[
"LBS/GAL"][
"LBS/GAL"] = 1.0;
244 Element::~Element(
void)
246 for (
unsigned int i = 0; i < children.size(); ++i)
247 children[i]->SetParent(0);
252 string Element::GetAttributeValue(
const string& attr)
254 if (HasAttribute(attr))
return attributes[attr];
260 bool Element::SetAttributeValue(
const std::string& key,
const std::string& value)
262 bool ret = HasAttribute(key);
264 attributes[key] = value;
271 double Element::GetAttributeValueAsNumber(
const string& attr)
273 string attribute = GetAttributeValue(attr);
275 if (attribute.empty()) {
276 cerr << ReadFrom() <<
"Expecting numeric attribute value, but got no data" 282 if (is_number(trim(attribute)))
283 number = atof(attribute.c_str());
285 cerr << ReadFrom() <<
"Expecting numeric attribute value, but got: " 286 << attribute << endl;
298 if (children.size() > el) {
312 if (children.size() > element_index+1) {
314 return children[element_index];
323 string Element::GetDataLine(
unsigned int i)
325 if (data_lines.size() > 0)
return data_lines[i];
326 else return string(
"");
331 double Element::GetDataAsNumber(
void)
333 if (data_lines.size() == 1) {
335 if (is_number(trim(data_lines[0])))
336 number = atof(data_lines[0].c_str());
338 cerr << ReadFrom() <<
"Expected numeric value, but got: " << data_lines[0]
344 }
else if (data_lines.size() == 0) {
345 cerr << ReadFrom() <<
"Expected numeric value, but got no data" << endl;
348 cerr << ReadFrom() <<
"Attempting to get single data value in element " 349 <<
"<" << name <<
">" << endl
350 <<
" from multiple lines:" << endl;
351 for(
unsigned int i=0; i<data_lines.size(); ++i)
352 cerr << data_lines[i] << endl;
359 unsigned int Element::GetNumElements(
const string& element_name)
361 unsigned int number_of_elements=0;
362 Element* el=FindElement(element_name);
364 number_of_elements++;
365 el=FindNextElement(element_name);
367 return number_of_elements;
372 Element* Element::FindElement(
const string& el)
374 if (el.empty() && children.size() >= 1) {
378 for (
unsigned int i=0; i<children.size(); i++) {
379 if (el == children[i]->GetName()) {
390 Element* Element::FindNextElement(
const string& el)
393 if (element_index < children.size()) {
394 return children[element_index++];
400 for (
unsigned int i=element_index; i<children.size(); i++) {
401 if (el == children[i]->GetName()) {
412 double Element::FindElementValueAsNumber(
const string& el)
414 Element* element = FindElement(el);
417 value = DisperseValue(element, value);
420 cerr << ReadFrom() <<
"Attempting to get non-existent element " << el
428 string Element::FindElementValue(
const string& el)
430 Element* element = FindElement(el);
440 double Element::FindElementValueAsNumberConvertTo(
const string& el,
const string& target_units)
442 Element* element = FindElement(el);
445 cerr << ReadFrom() <<
"Attempting to get non-existent element " << el
452 if (!supplied_units.empty()) {
453 if (convert.find(supplied_units) == convert.end()) {
454 cerr << element->
ReadFrom() <<
"Supplied unit: \"" 455 << supplied_units <<
"\" does not exist (typo?)." << endl;
458 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
459 cerr << element->
ReadFrom() <<
"Supplied unit: \"" 460 << supplied_units <<
"\" cannot be converted to " << target_units
469 if ((supplied_units ==
"RAD") && (fabs(value) > 2 * M_PI)) {
471 << value <<
" RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]" 474 if ((supplied_units ==
"DEG") && (fabs(value) > 360.0)) {
476 << value <<
" DEG is outside the range [ -360 DEG ; +360 DEG ]" 481 if (!supplied_units.empty()) {
482 value *= convert[supplied_units][target_units];
485 if ((target_units ==
"RAD") && (fabs(value) > 2 * M_PI)) {
487 << value <<
" RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]" 490 if ((target_units ==
"DEG") && (fabs(value) > 360.0)) {
492 << value <<
" DEG is outside the range [ -360 DEG ; +360 DEG ]" 496 value = DisperseValue(element, value, supplied_units, target_units);
503 double Element::FindElementValueAsNumberConvertFromTo(
const string& el,
504 const string& supplied_units,
505 const string& target_units)
507 Element* element = FindElement(el);
510 cerr <<
"Attempting to get non-existent element " << el << endl;
514 if (!supplied_units.empty()) {
515 if (convert.find(supplied_units) == convert.end()) {
516 cerr << element->
ReadFrom() <<
"Supplied unit: \"" 517 << supplied_units <<
"\" does not exist (typo?)." << endl;
520 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
521 cerr << element->
ReadFrom() <<
"Supplied unit: \"" 522 << supplied_units <<
"\" cannot be converted to " << target_units
529 if (!supplied_units.empty()) {
530 value *= convert[supplied_units][target_units];
533 value = DisperseValue(element, value, supplied_units, target_units);
545 string supplied_units = GetAttributeValue(
"unit");
547 if (!supplied_units.empty()) {
548 if (convert.find(supplied_units) == convert.end()) {
549 cerr << ReadFrom() <<
"Supplied unit: \"" 550 << supplied_units <<
"\" does not exist (typo?)." << endl;
553 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
554 cerr << ReadFrom() <<
"Supplied unit: \"" 555 << supplied_units <<
"\" cannot be converted to " << target_units
561 item = FindElement(
"x");
562 if (!item) item = FindElement(
"roll");
565 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
566 triplet(1) = DisperseValue(item, value, supplied_units, target_units);
572 item = FindElement(
"y");
573 if (!item) item = FindElement(
"pitch");
576 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
577 triplet(2) = DisperseValue(item, value, supplied_units, target_units);
582 item = FindElement(
"z");
583 if (!item) item = FindElement(
"yaw");
586 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
587 triplet(3) = DisperseValue(item, value, supplied_units, target_units);
597 double Element::DisperseValue(
Element *e,
double val,
const std::string& supplied_units,
598 const std::string& target_units)
602 bool disperse =
false;
604 char* num = getenv(
"JSBSIM_DISPERSE");
606 disperse = (atoi(num) == 1);
610 std::cerr <<
"Could not process JSBSIM_DISPERSE environment variable: Assumed NO dispersions." << endl;
615 if (!supplied_units.empty()) disp *= convert[supplied_units][target_units];
617 if (attType ==
"gaussian" || attType ==
"gaussiansigned") {
618 double grn = FGJSBBase::GaussianRandomNumber();
619 if (attType ==
"gaussian") {
620 value = val + disp*grn;
622 value = (val + disp*grn)*(fabs(grn)/grn);
624 }
else if (attType ==
"uniform" || attType ==
"uniformsigned") {
625 double urn = ((((double)rand()/RAND_MAX)-0.5)*2.0);
626 if (attType ==
"uniform") {
627 value = val + disp * urn;
629 value = (val + disp * urn)*(fabs(urn)/urn);
632 cerr << ReadFrom() <<
"Unknown dispersion type" << attType << endl;
642 void Element::Print(
unsigned int level)
644 unsigned int i, spaces;
647 for (spaces=0; spaces<=level; spaces++) cout <<
" ";
648 cout <<
"Element Name: " << name;
650 map<string, string>::iterator it;
651 for (it = attributes.begin(); it != attributes.end(); ++it)
652 cout <<
" " << it->first <<
" = " << it->second;
655 for (i=0; i<data_lines.size(); i++) {
656 for (spaces=0; spaces<=level; spaces++) cout <<
" ";
657 cout << data_lines[i] << endl;
659 for (i=0; i<children.size(); i++) {
660 children[i]->Print(level);
666 void Element::AddAttribute(
const string& name,
const string& value)
668 attributes[name] = value;
673 void Element::AddData(
string d)
675 string::size_type string_start = d.find_first_not_of(
" \t");
676 if (string_start != string::npos && string_start > 0) {
677 d.erase(0,string_start);
679 data_lines.push_back(d);
684 string Element::ReadFrom(
void)
const 686 ostringstream message;
689 <<
"In file " << GetFileName() <<
": line " << GetLineNumber()
692 return message.str();
699 map<string, string>::iterator it;
701 for (it=el->attributes.begin(); it != el->attributes.end(); ++it) {
702 if (attributes.find(it->first) == attributes.end())
703 attributes[it->first] = it->second;
705 if (FGJSBBase::debug_lvl > 0 && (attributes[it->first] != it->second))
706 cout << el->
ReadFrom() <<
" Attribute '" << it->first <<
"' is overridden in file " 707 << GetFileName() <<
": line " << GetLineNumber() << endl
708 <<
" The value '" << attributes[it->first] <<
"' will be used instead of '" 709 << it->second <<
"'." << endl;
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
double GetDataAsNumber(void)
Converts the element data to a number.
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
const std::string & GetName(void) const
Retrieves the element name.
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to an element.
This class implements a 3 element column vector.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...