1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4 Date started: 09/28/2004
5 Purpose: XML element class
8 ------------- Copyright (C) 2001 Jon S. Berndt (jon@jsbsim.org) -------------
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 Software
12 Foundation; either version 2 of the License, or (at your option) any later
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
20 You should have received a copy of the GNU Lesser General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 Place - Suite 330, Boston, MA 02111-1307, USA.
24 Further information about the GNU Lesser General Public License can also be found on
25 the world wide web at http://www.gnu.org.
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
31 #include "FGXMLElement.h"
39 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
41 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
45 static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.33 2011/08/05 12:28:20 jberndt Exp $";
46 static const char *IdHdr = ID_XMLELEMENT;
48 bool Element::converterIsInitialized = false;
49 map <string, map <string, double> > Element::convert;
51 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55 Element::Element(const string& nm)
61 if (!converterIsInitialized) {
62 converterIsInitialized = true;
63 // convert ["from"]["to"] = factor, so: from * factor = to
65 convert["M"]["FT"] = 3.2808399;
66 convert["FT"]["M"] = 1.0/convert["M"]["FT"];
67 convert["CM"]["FT"] = 0.032808399;
68 convert["FT"]["CM"] = 1.0/convert["CM"]["FT"];
69 convert["KM"]["FT"] = 3280.8399;
70 convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
71 convert["FT"]["IN"] = 12.0;
72 convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
73 convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
74 convert["M"]["IN"] = convert["M"]["FT"] * convert["FT"]["IN"];
76 convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
77 convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
78 convert["CM2"]["FT2"] = convert["CM"]["FT"]*convert["CM"]["FT"];
79 convert["FT2"]["CM2"] = 1.0/convert["CM2"]["FT2"];
80 convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
81 convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
82 convert["FT2"]["IN2"] = 144.0;
83 convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
85 convert["IN3"]["CC"] = 16.387064;
86 convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
87 convert["FT3"]["IN3"] = 1728.0;
88 convert["IN3"]["FT3"] = 1.0/convert["FT3"]["IN3"];
89 convert["M3"]["FT3"] = 35.3146667;
90 convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"];
91 convert["LTR"]["IN3"] = 61.0237441;
92 convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"];
94 convert["LBS"]["KG"] = 0.45359237;
95 convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
96 convert["SLUG"]["KG"] = 14.59390;
97 convert["KG"]["SLUG"] = 1.0/convert["SLUG"]["KG"];
99 convert["SLUG*FT2"]["KG*M2"] = 1.35594;
100 convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
102 convert["RAD"]["DEG"] = 180.0/M_PI;
103 convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
105 convert["RAD/SEC"]["DEG/SEC"] = convert["RAD"]["DEG"];
106 convert["DEG/SEC"]["RAD/SEC"] = 1.0/convert["RAD/SEC"]["DEG/SEC"];
108 convert["LBS/FT"]["N/M"] = 14.5939;
109 convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
111 convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
112 convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
113 // Damping force (Square Law)
114 convert["LBS/FT2/SEC2"]["N/M2/SEC2"] = 47.880259;
115 convert["N/M2/SEC2"]["LBS/FT2/SEC2"] = 1.0/convert["LBS/FT2/SEC2"]["N/M2/SEC2"];
117 convert["WATTS"]["HP"] = 0.001341022;
118 convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
120 convert["N"]["LBS"] = 0.22482;
121 convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
123 convert["KTS"]["FT/SEC"] = 1.68781;
124 convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
125 convert["M/S"]["FT/S"] = 3.2808399;
126 convert["M/SEC"]["FT/SEC"] = 3.2808399;
127 convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
128 convert["M/SEC"]["FT/SEC"] = 3.2808399;
129 convert["FT/SEC"]["M/SEC"] = 1.0/convert["M/SEC"]["FT/SEC"];
130 convert["KM/SEC"]["FT/SEC"] = 3280.8399;
131 convert["FT/SEC"]["KM/SEC"] = 1.0/convert["KM/SEC"]["FT/SEC"];
133 convert["FT*LBS"]["N*M"] = 1.35581795;
134 convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
136 convert["M4*SEC/KG"]["FT4*SEC/SLUG"] = convert["M"]["FT"]*convert["M"]["FT"]*
137 convert["M"]["FT"]*convert["M"]["FT"]/convert["KG"]["SLUG"];
138 convert["FT4*SEC/SLUG"]["M4*SEC/KG"] =
139 1.0/convert["M4*SEC/KG"]["FT4*SEC/SLUG"];
141 convert["INHG"]["PSF"] = 70.7180803;
142 convert["PSF"]["INHG"] = 1.0/convert["INHG"]["PSF"];
143 convert["ATM"]["INHG"] = 29.9246899;
144 convert["INHG"]["ATM"] = 1.0/convert["ATM"]["INHG"];
145 convert["PSI"]["INHG"] = 2.03625437;
146 convert["INHG"]["PSI"] = 1.0/convert["PSI"]["INHG"];
147 convert["INHG"]["PA"] = 3386.0; // inches Mercury to pascals
148 convert["PA"]["INHG"] = 1.0/convert["INHG"]["PA"];
149 convert["LBS/FT2"]["N/M2"] = 14.5939/convert["FT"]["M"];
150 convert["N/M2"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["N/M2"];
151 convert["LBS/FT2"]["PA"] = convert["LBS/FT2"]["N/M2"];
152 convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
154 convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
156 convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
157 convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
159 convert["KG/L"]["LBS/GAL"] = 8.3454045;
160 convert["LBS/GAL"]["KG/L"] = 1.0/convert["KG/L"]["LBS/GAL"];
163 convert["M"]["M"] = 1.00;
164 convert["KM"]["KM"] = 1.00;
165 convert["FT"]["FT"] = 1.00;
166 convert["IN"]["IN"] = 1.00;
168 convert["M2"]["M2"] = 1.00;
169 convert["FT2"]["FT2"] = 1.00;
171 convert["IN3"]["IN3"] = 1.00;
172 convert["CC"]["CC"] = 1.0;
173 convert["M3"]["M3"] = 1.0;
174 convert["FT3"]["FT3"] = 1.0;
175 convert["LTR"]["LTR"] = 1.0;
177 convert["KG"]["KG"] = 1.00;
178 convert["LBS"]["LBS"] = 1.00;
179 // Moments of Inertia
180 convert["KG*M2"]["KG*M2"] = 1.00;
181 convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
183 convert["DEG"]["DEG"] = 1.00;
184 convert["RAD"]["RAD"] = 1.00;
186 convert["DEG/SEC"]["DEG/SEC"] = 1.00;
187 convert["RAD/SEC"]["RAD/SEC"] = 1.00;
189 convert["LBS/FT"]["LBS/FT"] = 1.00;
190 convert["N/M"]["N/M"] = 1.00;
192 convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
193 convert["N/M/SEC"]["N/M/SEC"] = 1.00;
194 // Damping force (Square law)
195 convert["LBS/FT2/SEC2"]["LBS/FT2/SEC2"] = 1.00;
196 convert["N/M2/SEC2"]["N/M2/SEC2"] = 1.00;
198 convert["HP"]["HP"] = 1.00;
199 convert["WATTS"]["WATTS"] = 1.00;
201 convert["N"]["N"] = 1.00;
203 convert["FT/SEC"]["FT/SEC"] = 1.00;
204 convert["KTS"]["KTS"] = 1.00;
205 convert["M/S"]["M/S"] = 1.0;
206 convert["M/SEC"]["M/SEC"] = 1.0;
207 convert["KM/SEC"]["KM/SEC"] = 1.0;
209 convert["FT*LBS"]["FT*LBS"] = 1.00;
210 convert["N*M"]["N*M"] = 1.00;
212 convert["M4*SEC/KG"]["M4*SEC/KG"] = 1.0;
213 convert["FT4*SEC/SLUG"]["FT4*SEC/SLUG"] = 1.0;
215 convert["PSI"]["PSI"] = 1.00;
216 convert["PSF"]["PSF"] = 1.00;
217 convert["INHG"]["INHG"] = 1.00;
218 convert["ATM"]["ATM"] = 1.0;
219 convert["PA"]["PA"] = 1.0;
220 convert["N/M2"]["N/M2"] = 1.00;
221 convert["LBS/FT2"]["LBS/FT2"] = 1.00;
223 convert["LBS/SEC"]["LBS/SEC"] = 1.00;
224 convert["KG/MIN"]["KG/MIN"] = 1.0;
225 convert["LBS/MIN"]["LBS/MIN"] = 1.0;
227 convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
228 convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
230 convert["KG/L"]["KG/L"] = 1.0;
231 convert["LBS/GAL"]["LBS/GAL"] = 1.0;
235 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
237 Element::~Element(void)
239 for (unsigned int i=0; i<children.size(); i++) delete children[i];
242 attribute_key.clear();
245 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247 string Element::GetAttributeValue(const string& attr)
250 for (unsigned int i=0; i<attribute_key.size(); i++) {
251 if (attribute_key[i] == attr) select = i;
253 if (select < 0) return string("");
254 else return attributes[attr];
257 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
259 double Element::GetAttributeValueAsNumber(const string& attr)
261 string attribute = GetAttributeValue(attr);
263 if (attribute.empty()) return HUGE_VAL;
264 else return (atof(attribute.c_str()));
267 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269 Element* Element::GetElement(unsigned int el)
271 if (children.size() > el) {
281 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
283 Element* Element::GetNextElement(void)
285 if (children.size() > element_index+1) {
287 return children[element_index];
294 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
296 string Element::GetDataLine(unsigned int i)
298 if (data_lines.size() > 0) return data_lines[i];
299 else return string("");
302 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304 double Element::GetDataAsNumber(void)
306 if (data_lines.size() == 1) {
307 return atof(data_lines[0].c_str());
308 } else if (data_lines.size() == 0) {
311 cerr << "Attempting to get single data value from multiple lines in element " << name << endl;
316 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318 unsigned int Element::GetNumElements(const string& element_name)
320 unsigned int number_of_elements=0;
321 Element* el=FindElement(element_name);
323 number_of_elements++;
324 el=FindNextElement(element_name);
326 return number_of_elements;
329 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331 Element* Element::FindElement(const string& el)
333 if (el.empty() && children.size() >= 1) {
337 for (unsigned int i=0; i<children.size(); i++) {
338 if (el == children[i]->GetName()) {
347 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349 Element* Element::FindNextElement(const string& el)
352 if (element_index < children.size()) {
353 return children[element_index++];
359 for (unsigned int i=element_index; i<children.size(); i++) {
360 if (el == children[i]->GetName()) {
369 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
371 double Element::FindElementValueAsNumber(const string& el)
373 Element* element = FindElement(el);
375 return element->GetDataAsNumber();
377 cerr << "Attempting to get single data value from multiple lines" << endl;
382 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 string Element::FindElementValue(const string& el)
386 Element* element = FindElement(el);
388 return element->GetDataLine();
394 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396 double Element::FindElementValueAsNumberConvertTo(const string& el, const string& target_units)
398 Element* element = FindElement(el);
401 cerr << "Attempting to get non-existent element " << el << endl;
405 string supplied_units = element->GetAttributeValue("unit");
407 if (!supplied_units.empty()) {
408 if (convert.find(supplied_units) == convert.end()) {
409 cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
410 << " conversion in FGXMLElement.cpp." << endl;
413 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
414 cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
415 << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
420 double value = element->GetDataAsNumber();
421 if (!supplied_units.empty()) {
422 value *= convert[supplied_units][target_units];
428 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 double Element::FindElementValueAsNumberConvertFromTo( const string& el,
431 const string& supplied_units,
432 const string& target_units)
434 Element* element = FindElement(el);
437 cerr << "Attempting to get non-existent element " << el << endl;
441 if (!supplied_units.empty()) {
442 if (convert.find(supplied_units) == convert.end()) {
443 cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
444 << " conversion in FGXMLElement.cpp." << endl;
447 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
448 cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
449 << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
454 double value = element->GetDataAsNumber();
455 if (!supplied_units.empty()) {
456 value *= convert[supplied_units][target_units];
462 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464 FGColumnVector3 Element::FindElementTripletConvertTo( const string& target_units)
466 FGColumnVector3 triplet;
469 string supplied_units = GetAttributeValue("unit");
471 if (!supplied_units.empty()) {
472 if (convert.find(supplied_units) == convert.end()) {
473 cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
474 << " conversion in FGXMLElement.cpp." << endl;
477 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
478 cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
479 << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
484 item = FindElement("x");
485 if (!item) item = FindElement("roll");
487 value = item->GetDataAsNumber();
488 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
494 item = FindElement("y");
495 if (!item) item = FindElement("pitch");
497 value = item->GetDataAsNumber();
498 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
504 item = FindElement("z");
505 if (!item) item = FindElement("yaw");
507 value = item->GetDataAsNumber();
508 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
517 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
519 void Element::Print(unsigned int level)
521 unsigned int i, spaces;
524 for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
525 cout << "Element Name: " << name;
526 for (i=0; i<attributes.size(); i++) {
527 cout << " " << attribute_key[i] << " = " << attributes[attribute_key[i]];
530 for (i=0; i<data_lines.size(); i++) {
531 for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
532 cout << data_lines[i] << endl;
534 for (i=0; i<children.size(); i++) {
535 children[i]->Print(level);
539 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
541 void Element::AddAttribute(const string& name, const string& value)
543 attribute_key.push_back(name);
544 attributes[name] = value;
547 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549 void Element::AddData(string d)
551 string::size_type string_start = d.find_first_not_of(" \t");
552 if (string_start != string::npos && string_start > 0) {
553 d.erase(0,string_start);
555 data_lines.push_back(d);
558 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560 } // end namespace JSBSim