JSBSim Flight Dynamics Model 1.0 (23 February 2013)
An Open Source Flight Dynamics and Control Software Library in C++

FGXMLElement.cpp

00001 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00002 
00003  Author:       Jon Berndt
00004  Date started: 09/28/2004
00005  Purpose:      XML element class
00006  Called by:    FGXMLParse
00007 
00008  ------------- Copyright (C) 2001  Jon S. Berndt (jon@jsbsim.org) -------------
00009 
00010  This program is free software; you can redistribute it and/or modify it under
00011  the terms of the GNU Lesser General Public License as published by the Free Software
00012  Foundation; either version 2 of the License, or (at your option) any later
00013  version.
00014 
00015  This program is distributed in the hope that it will be useful, but WITHOUT
00016  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00018  details.
00019 
00020  You should have received a copy of the GNU Lesser General Public License along with
00021  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00022  Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024  Further information about the GNU Lesser General Public License can also be found on
00025  the world wide web at http://www.gnu.org.
00026 
00027 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00028 INCLUDES
00029 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
00030 
00031 #include <cmath>
00032 #include <cstdlib>
00033 #include <iostream>
00034 
00035 #include "FGXMLElement.h"
00036 #include "string_utilities.h"
00037 
00038 using namespace std;
00039 
00040 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00041 FORWARD DECLARATIONS
00042 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
00043 
00044 namespace JSBSim {
00045 
00046 static const char *IdSrc = "$Id: FGXMLElement.cpp,v 1.38 2012/12/13 04:41:06 jberndt Exp $";
00047 static const char *IdHdr = ID_XMLELEMENT;
00048 
00049 bool Element::converterIsInitialized = false;
00050 map <string, map <string, double> > Element::convert;
00051 
00052 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00053 CLASS IMPLEMENTATION
00054 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
00055 
00056 Element::Element(const string& nm)
00057 {
00058   name   = nm;
00059   parent = 0L;
00060   element_index = 0;
00061 
00062   if (!converterIsInitialized) {
00063     converterIsInitialized = true;
00064     // convert ["from"]["to"] = factor, so: from * factor = to
00065     // Length
00066     convert["M"]["FT"] = 3.2808399;
00067     convert["FT"]["M"] = 1.0/convert["M"]["FT"];
00068     convert["CM"]["FT"] = 0.032808399;
00069     convert["FT"]["CM"] = 1.0/convert["CM"]["FT"];
00070     convert["KM"]["FT"] = 3280.8399;
00071     convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
00072     convert["FT"]["IN"] = 12.0;
00073     convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
00074     convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
00075     convert["M"]["IN"] = convert["M"]["FT"] * convert["FT"]["IN"];
00076     // Area
00077     convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
00078     convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
00079     convert["CM2"]["FT2"] = convert["CM"]["FT"]*convert["CM"]["FT"];
00080     convert["FT2"]["CM2"] = 1.0/convert["CM2"]["FT2"];
00081     convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
00082     convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
00083     convert["FT2"]["IN2"] = 144.0;
00084     convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
00085     // Volume
00086     convert["IN3"]["CC"] = 16.387064;
00087     convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
00088     convert["FT3"]["IN3"] = 1728.0;
00089     convert["IN3"]["FT3"] = 1.0/convert["FT3"]["IN3"];
00090     convert["M3"]["FT3"] = 35.3146667;
00091     convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"];
00092     convert["LTR"]["IN3"] = 61.0237441;
00093     convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"];
00094     // Mass & Weight
00095     convert["LBS"]["KG"] = 0.45359237;
00096     convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
00097     convert["SLUG"]["KG"] = 14.59390;
00098     convert["KG"]["SLUG"] = 1.0/convert["SLUG"]["KG"];
00099     // Moments of Inertia
00100     convert["SLUG*FT2"]["KG*M2"] = 1.35594;
00101     convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
00102     // Angles
00103     convert["RAD"]["DEG"] = 180.0/M_PI;
00104     convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
00105     // Angular rates
00106     convert["RAD/SEC"]["DEG/SEC"] = convert["RAD"]["DEG"];
00107     convert["DEG/SEC"]["RAD/SEC"] = 1.0/convert["RAD/SEC"]["DEG/SEC"];
00108     // Spring force
00109     convert["LBS/FT"]["N/M"] = 14.5939;
00110     convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
00111     // Damping force
00112     convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
00113     convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
00114     // Damping force (Square Law)
00115     convert["LBS/FT2/SEC2"]["N/M2/SEC2"] = 47.880259;
00116     convert["N/M2/SEC2"]["LBS/FT2/SEC2"] = 1.0/convert["LBS/FT2/SEC2"]["N/M2/SEC2"];
00117     // Power
00118     convert["WATTS"]["HP"] = 0.001341022;
00119     convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
00120     // Force
00121     convert["N"]["LBS"] = 0.22482;
00122     convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
00123     // Velocity
00124     convert["KTS"]["FT/SEC"] = 1.68781;
00125     convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
00126     convert["M/S"]["FT/S"] = 3.2808399;
00127     convert["M/SEC"]["FT/SEC"] = 3.2808399;
00128     convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
00129     convert["M/SEC"]["FT/SEC"] = 3.2808399;
00130     convert["FT/SEC"]["M/SEC"] = 1.0/convert["M/SEC"]["FT/SEC"];
00131     convert["KM/SEC"]["FT/SEC"] = 3280.8399;
00132     convert["FT/SEC"]["KM/SEC"] = 1.0/convert["KM/SEC"]["FT/SEC"];
00133     // Torque
00134     convert["FT*LBS"]["N*M"] = 1.35581795;
00135     convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
00136     // Valve
00137     convert["M4*SEC/KG"]["FT4*SEC/SLUG"] = convert["M"]["FT"]*convert["M"]["FT"]*
00138       convert["M"]["FT"]*convert["M"]["FT"]/convert["KG"]["SLUG"];
00139     convert["FT4*SEC/SLUG"]["M4*SEC/KG"] =
00140       1.0/convert["M4*SEC/KG"]["FT4*SEC/SLUG"];
00141     // Pressure
00142     convert["INHG"]["PSF"] = 70.7180803;
00143     convert["PSF"]["INHG"] = 1.0/convert["INHG"]["PSF"];
00144     convert["ATM"]["INHG"] = 29.9246899;
00145     convert["INHG"]["ATM"] = 1.0/convert["ATM"]["INHG"];
00146     convert["PSI"]["INHG"] = 2.03625437;
00147     convert["INHG"]["PSI"] = 1.0/convert["PSI"]["INHG"];
00148     convert["INHG"]["PA"] = 3386.0; // inches Mercury to pascals
00149     convert["PA"]["INHG"] = 1.0/convert["INHG"]["PA"];
00150     convert["LBS/FT2"]["N/M2"] = 14.5939/convert["FT"]["M"];
00151     convert["N/M2"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["N/M2"];
00152     convert["LBS/FT2"]["PA"] = convert["LBS/FT2"]["N/M2"];
00153     convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
00154     // Mass flow
00155     convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
00156     // Fuel Consumption
00157     convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
00158     convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
00159     // Density
00160     convert["KG/L"]["LBS/GAL"] = 8.3454045;
00161     convert["LBS/GAL"]["KG/L"] = 1.0/convert["KG/L"]["LBS/GAL"];
00162 
00163     // Length
00164     convert["M"]["M"] = 1.00;
00165     convert["KM"]["KM"] = 1.00;
00166     convert["FT"]["FT"] = 1.00;
00167     convert["IN"]["IN"] = 1.00;
00168     // Area
00169     convert["M2"]["M2"] = 1.00;
00170     convert["FT2"]["FT2"] = 1.00;
00171     // Volume
00172     convert["IN3"]["IN3"] = 1.00;
00173     convert["CC"]["CC"] = 1.0;
00174     convert["M3"]["M3"] = 1.0;
00175     convert["FT3"]["FT3"] = 1.0;
00176     convert["LTR"]["LTR"] = 1.0;
00177     // Mass & Weight
00178     convert["KG"]["KG"] = 1.00;
00179     convert["LBS"]["LBS"] = 1.00;
00180     // Moments of Inertia
00181     convert["KG*M2"]["KG*M2"] = 1.00;
00182     convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
00183     // Angles
00184     convert["DEG"]["DEG"] = 1.00;
00185     convert["RAD"]["RAD"] = 1.00;
00186     // Angular rates
00187     convert["DEG/SEC"]["DEG/SEC"] = 1.00;
00188     convert["RAD/SEC"]["RAD/SEC"] = 1.00;
00189     // Spring force
00190     convert["LBS/FT"]["LBS/FT"] = 1.00;
00191     convert["N/M"]["N/M"] = 1.00;
00192     // Damping force
00193     convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
00194     convert["N/M/SEC"]["N/M/SEC"] = 1.00;
00195     // Damping force (Square law)
00196     convert["LBS/FT2/SEC2"]["LBS/FT2/SEC2"] = 1.00;
00197     convert["N/M2/SEC2"]["N/M2/SEC2"] = 1.00;
00198     // Power
00199     convert["HP"]["HP"] = 1.00;
00200     convert["WATTS"]["WATTS"] = 1.00;
00201     // Force
00202     convert["N"]["N"] = 1.00;
00203     // Velocity
00204     convert["FT/SEC"]["FT/SEC"] = 1.00;
00205     convert["KTS"]["KTS"] = 1.00;
00206     convert["M/S"]["M/S"] = 1.0;
00207     convert["M/SEC"]["M/SEC"] = 1.0;
00208     convert["KM/SEC"]["KM/SEC"] = 1.0;
00209     // Torque
00210     convert["FT*LBS"]["FT*LBS"] = 1.00;
00211     convert["N*M"]["N*M"] = 1.00;
00212     // Valve
00213     convert["M4*SEC/KG"]["M4*SEC/KG"] = 1.0;
00214     convert["FT4*SEC/SLUG"]["FT4*SEC/SLUG"] = 1.0;
00215     // Pressure
00216     convert["PSI"]["PSI"] = 1.00;
00217     convert["PSF"]["PSF"] = 1.00;
00218     convert["INHG"]["INHG"] = 1.00;
00219     convert["ATM"]["ATM"] = 1.0;
00220     convert["PA"]["PA"] = 1.0;
00221     convert["N/M2"]["N/M2"] = 1.00;
00222     convert["LBS/FT2"]["LBS/FT2"] = 1.00;
00223     // Mass flow
00224     convert["LBS/SEC"]["LBS/SEC"] = 1.00;
00225     convert["KG/MIN"]["KG/MIN"] = 1.0;
00226     convert["LBS/MIN"]["LBS/MIN"] = 1.0;
00227     // Fuel Consumption
00228     convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
00229     convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
00230     // Density
00231     convert["KG/L"]["KG/L"] = 1.0;
00232     convert["LBS/GAL"]["LBS/GAL"] = 1.0;
00233   }
00234   attribute_key.resize(0);
00235 }
00236 
00237 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00238 
00239 Element::~Element(void)
00240 {
00241   for (unsigned int i=0; i<children.size(); i++) delete children[i];
00242   data_lines.clear();
00243   attributes.clear();
00244   attribute_key.clear();
00245 }
00246 
00247 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00248 
00249 string Element::GetAttributeValue(const string& attr)
00250 {
00251   if (HasAttribute(attr))  return attributes[attr];
00252   else                     return ("");
00253 }
00254 
00255 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00256 
00257 bool Element::HasAttribute(const string& attr)
00258 {
00259   bool status=true;
00260   int select=-1;
00261 
00262   unsigned int attr_cnt = attribute_key.size();
00263 
00264   for (unsigned int i=0; i<attr_cnt; i++) {
00265     if (attribute_key[i] == attr) select = i;
00266   }
00267   if (select < 0) status=false;
00268   return status;
00269 }
00270 
00271 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00272 
00273 double Element::GetAttributeValueAsNumber(const string& attr)
00274 {
00275   string attribute = GetAttributeValue(attr);
00276 
00277   if (attribute.empty()) return HUGE_VAL;
00278   else {
00279     double number=0;
00280     if (is_number(trim(attribute)))
00281       number = atof(attribute.c_str());
00282     else
00283       throw("Expecting numeric attribute value, but got: " + attribute);
00284     
00285     return (number);
00286   }
00287 }
00288 
00289 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00290 
00291 Element* Element::GetElement(unsigned int el)
00292 {
00293   if (children.size() > el) {
00294     element_index = el;
00295     return children[el];
00296   }
00297   else {
00298     element_index = 0;
00299     return 0L;
00300   }
00301 }
00302 
00303 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00304 
00305 Element* Element::GetNextElement(void)
00306 {
00307   if (children.size() > element_index+1) {
00308     element_index++;
00309     return children[element_index];
00310   } else {
00311     element_index = 0;
00312     return 0L;
00313   }
00314 }
00315 
00316 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00317 
00318 string Element::GetDataLine(unsigned int i)
00319 {
00320   if (data_lines.size() > 0) return data_lines[i];
00321   else return string("");
00322 }
00323 
00324 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00325 
00326 double Element::GetDataAsNumber(void)
00327 {
00328   if (data_lines.size() == 1) {
00329     double number=0;
00330     if (is_number(trim(data_lines[0])))
00331       number = atof(data_lines[0].c_str());
00332     else
00333       throw("Expected numeric value, but got: " + data_lines[0]);
00334 
00335     return number;
00336   } else if (data_lines.size() == 0) {
00337     return HUGE_VAL;
00338   } else {
00339     cerr << "Attempting to get single data value from multiple lines in element " << name << endl;
00340     return HUGE_VAL;
00341   }
00342 }
00343 
00344 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00345 
00346 unsigned int Element::GetNumElements(const string& element_name)
00347 {
00348   unsigned int number_of_elements=0;
00349   Element* el=FindElement(element_name);
00350   while (el) {
00351     number_of_elements++;
00352     el=FindNextElement(element_name);
00353   }
00354   return number_of_elements;
00355 }
00356 
00357 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00358 
00359 Element* Element::FindElement(const string& el)
00360 {
00361   if (el.empty() && children.size() >= 1) {
00362     element_index = 1;
00363     return children[0];
00364   }
00365   for (unsigned int i=0; i<children.size(); i++) {
00366     if (el == children[i]->GetName()) {
00367       element_index = i+1;
00368       return children[i];
00369     }
00370   }
00371   element_index = 0;
00372   return 0L;
00373 }
00374 
00375 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00376 
00377 Element* Element::FindNextElement(const string& el)
00378 {
00379   if (el.empty()) {
00380     if (element_index < children.size()) {
00381       return children[element_index++];
00382     } else {
00383       element_index = 0;
00384       return 0L;
00385     }
00386   }
00387   for (unsigned int i=element_index; i<children.size(); i++) {
00388     if (el == children[i]->GetName()) {
00389       element_index = i+1;
00390       return children[i];
00391     }
00392   }
00393   element_index = 0;
00394   return 0L;
00395 }
00396 
00397 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00398 
00399 double Element::FindElementValueAsNumber(const string& el)
00400 {
00401   Element* element = FindElement(el);
00402   if (element) {
00403     double value = element->GetDataAsNumber();
00404     value = DisperseValue(element, value);
00405     return value;
00406   } else {
00407     cerr << "Attempting to get single data value from multiple lines" << endl;
00408     return 0;
00409   }
00410 }
00411 
00412 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00413 
00414 string Element::FindElementValue(const string& el)
00415 {
00416   Element* element = FindElement(el);
00417   if (element) {
00418     return element->GetDataLine();
00419   } else {
00420     return "";
00421   }
00422 }
00423 
00424 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00425 
00426 double Element::FindElementValueAsNumberConvertTo(const string& el, const string& target_units)
00427 {
00428   Element* element = FindElement(el);
00429 
00430   if (!element) {
00431     cerr << "Attempting to get non-existent element " << el << endl;
00432     exit(0);
00433   }
00434 
00435   string supplied_units = element->GetAttributeValue("unit");
00436 
00437   if (!supplied_units.empty()) {
00438     if (convert.find(supplied_units) == convert.end()) {
00439       cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
00440            << " conversion in FGXMLElement.cpp." << endl;
00441       exit(-1);
00442     }
00443     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
00444       cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
00445                    << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
00446       exit(-1);
00447     }
00448   }
00449 
00450   double value = element->GetDataAsNumber();
00451   if (!supplied_units.empty()) {
00452     value *= convert[supplied_units][target_units];
00453   }
00454 
00455   value = DisperseValue(element, value, supplied_units, target_units);
00456 
00457   return value;
00458 }
00459 
00460 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00461 
00462 double Element::FindElementValueAsNumberConvertFromTo( const string& el,
00463                                                        const string& supplied_units,
00464                                                        const string& target_units)
00465 {
00466   Element* element = FindElement(el);
00467 
00468   if (!element) {
00469     cerr << "Attempting to get non-existent element " << el << endl;
00470     exit(0);
00471   }
00472 
00473   if (!supplied_units.empty()) {
00474     if (convert.find(supplied_units) == convert.end()) {
00475       cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
00476            << " conversion in FGXMLElement.cpp." << endl;
00477       exit(-1);
00478     }
00479     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
00480       cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
00481                    << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
00482       exit(-1);
00483     }
00484   }
00485 
00486   double value = element->GetDataAsNumber();
00487   if (!supplied_units.empty()) {
00488     value *= convert[supplied_units][target_units];
00489   }
00490 
00491   value = DisperseValue(element, value, supplied_units, target_units);
00492 
00493   return value;
00494 }
00495 
00496 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00497 
00498 FGColumnVector3 Element::FindElementTripletConvertTo( const string& target_units)
00499 {
00500   FGColumnVector3 triplet;
00501   Element* item;
00502   double value=0.0;
00503   string supplied_units = GetAttributeValue("unit");
00504 
00505   if (!supplied_units.empty()) {
00506     if (convert.find(supplied_units) == convert.end()) {
00507       cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
00508            << " conversion in FGXMLElement.cpp." << endl;
00509       exit(-1);
00510     }
00511     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
00512       cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
00513                    << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
00514       exit(-1);
00515     }
00516   }
00517 
00518   item = FindElement("x");
00519   if (!item) item = FindElement("roll");
00520   if (item) {
00521     value = item->GetDataAsNumber();
00522     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
00523     triplet(1) = DisperseValue(item, value, supplied_units, target_units);
00524   } else {
00525     triplet(1) = 0.0;
00526   }
00527   
00528 
00529   item = FindElement("y");
00530   if (!item) item = FindElement("pitch");
00531   if (item) {
00532     value = item->GetDataAsNumber();
00533     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
00534     triplet(2) = DisperseValue(item, value, supplied_units, target_units);
00535   } else {
00536     triplet(2) = 0.0;
00537   }
00538 
00539   item = FindElement("z");
00540   if (!item) item = FindElement("yaw");
00541   if (item) {
00542     value = item->GetDataAsNumber();
00543     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
00544     triplet(3) = DisperseValue(item, value, supplied_units, target_units);
00545   } else {
00546     triplet(3) = 0.0;
00547   }
00548 
00549   return triplet;
00550 }
00551 
00552 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00553 
00554 double Element::DisperseValue(Element *e, double val, const std::string supplied_units, const std::string target_units)
00555 {
00556   double value=val;
00557   double disp=0.0;
00558   if (e->HasAttribute("dispersion")) {
00559     disp = e->GetAttributeValueAsNumber("dispersion");
00560     if (!supplied_units.empty()) disp *= convert[supplied_units][target_units];
00561     string attType = e->GetAttributeValue("type");
00562     if (attType == "gaussian") {
00563       value = val + disp*GaussianRandomNumber();
00564     } else if (attType == "uniform") {
00565       value = val + disp * ((((double)rand()/RAND_MAX)-0.5)*2.0);
00566     } else {
00567       std::cerr << "Unknown dispersion type" << endl;
00568       throw("Unknown dispersion type");
00569     }
00570 
00571   }
00572   return value;
00573 }
00574 
00575 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00576 
00577 double Element::GaussianRandomNumber(void)
00578 {
00579   static double V1, V2, S;
00580   static int phase = 0;
00581   double X;
00582 
00583   if (phase == 0) {
00584     V1 = V2 = S = X = 0.0;
00585 
00586     do {
00587       double U1 = (double)rand() / RAND_MAX;
00588       double U2 = (double)rand() / RAND_MAX;
00589 
00590       V1 = 2 * U1 - 1;
00591       V2 = 2 * U2 - 1;
00592       S = V1 * V1 + V2 * V2;
00593     } while(S >= 1 || S == 0);
00594 
00595     X = V1 * sqrt(-2 * log(S) / S);
00596   } else
00597     X = V2 * sqrt(-2 * log(S) / S);
00598 
00599   phase = 1 - phase;
00600 
00601   return X;
00602 }
00603 
00604 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00605 
00606 void Element::Print(unsigned int level)
00607 {
00608   unsigned int i, spaces;
00609 
00610   level+=2;
00611   for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
00612   cout << "Element Name: " << name;
00613   for (i=0; i<attributes.size(); i++) {
00614     cout << "  " << attribute_key[i] << " = " << attributes[attribute_key[i]];
00615   }
00616   cout << endl;
00617   for (i=0; i<data_lines.size(); i++) {
00618     for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
00619     cout << data_lines[i] << endl;
00620   }
00621   for (i=0; i<children.size(); i++) {
00622     children[i]->Print(level);
00623   }
00624 }
00625 
00626 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00627 
00628 void Element::AddAttribute(const string& name, const string& value)
00629 {
00630   attribute_key.push_back(name);
00631   attributes[name] = value;
00632 }
00633 
00634 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00635 
00636 void Element::AddData(string d)
00637 {
00638   string::size_type string_start = d.find_first_not_of(" \t");
00639   if (string_start != string::npos && string_start > 0) {
00640     d.erase(0,string_start);
00641   }
00642   data_lines.push_back(d);
00643 }
00644 
00645 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
00646 
00647 } // end namespace JSBSim