35#include "FGXMLElement.h"
37#include "input_output/string_utilities.h"
38#include "input_output/FGLog.h"
48bool Element::converterIsInitialized =
false;
49map <string, map <string, double> > Element::convert;
62 if (!converterIsInitialized) {
63 converterIsInitialized =
true;
66 convert[
"M"][
"FT"] = 3.2808399;
67 convert[
"FT"][
"M"] = 1.0/convert[
"M"][
"FT"];
68 convert[
"CM"][
"FT"] = 0.032808399;
69 convert[
"FT"][
"CM"] = 1.0/convert[
"CM"][
"FT"];
70 convert[
"KM"][
"FT"] = 3280.8399;
71 convert[
"FT"][
"KM"] = 1.0/convert[
"KM"][
"FT"];
72 convert[
"FT"][
"IN"] = 12.0;
73 convert[
"IN"][
"FT"] = 1.0/convert[
"FT"][
"IN"];
74 convert[
"IN"][
"M"] = convert[
"IN"][
"FT"] * convert[
"FT"][
"M"];
75 convert[
"M"][
"IN"] = convert[
"M"][
"FT"] * convert[
"FT"][
"IN"];
77 convert[
"M2"][
"FT2"] = convert[
"M"][
"FT"]*convert[
"M"][
"FT"];
78 convert[
"FT2"][
"M2"] = 1.0/convert[
"M2"][
"FT2"];
79 convert[
"CM2"][
"FT2"] = convert[
"CM"][
"FT"]*convert[
"CM"][
"FT"];
80 convert[
"FT2"][
"CM2"] = 1.0/convert[
"CM2"][
"FT2"];
81 convert[
"M2"][
"IN2"] = convert[
"M"][
"IN"]*convert[
"M"][
"IN"];
82 convert[
"IN2"][
"M2"] = 1.0/convert[
"M2"][
"IN2"];
83 convert[
"FT2"][
"IN2"] = 144.0;
84 convert[
"IN2"][
"FT2"] = 1.0/convert[
"FT2"][
"IN2"];
86 convert[
"IN3"][
"CC"] = 16.387064;
87 convert[
"CC"][
"IN3"] = 1.0/convert[
"IN3"][
"CC"];
88 convert[
"FT3"][
"IN3"] = 1728.0;
89 convert[
"IN3"][
"FT3"] = 1.0/convert[
"FT3"][
"IN3"];
90 convert[
"M3"][
"FT3"] = 35.3146667;
91 convert[
"FT3"][
"M3"] = 1.0/convert[
"M3"][
"FT3"];
92 convert[
"LTR"][
"IN3"] = 61.0237441;
93 convert[
"IN3"][
"LTR"] = 1.0/convert[
"LTR"][
"IN3"];
94 convert[
"GAL"][
"FT3"] = 0.133681;
95 convert[
"FT3"][
"GAL"] = 1.0/convert[
"GAL"][
"FT3"];
96 convert[
"IN3"][
"GAL"] = convert[
"IN3"][
"FT3"]*convert[
"FT3"][
"GAL"];
97 convert[
"LTR"][
"GAL"] = convert[
"LTR"][
"IN3"]*convert[
"IN3"][
"GAL"];
98 convert[
"M3"][
"GAL"] = 1000.*convert[
"LTR"][
"GAL"];
99 convert[
"CC"][
"GAL"] = convert[
"CC"][
"IN3"]*convert[
"IN3"][
"GAL"];
101 convert[
"LBS"][
"KG"] = 0.45359237;
102 convert[
"KG"][
"LBS"] = 1.0/convert[
"LBS"][
"KG"];
103 convert[
"SLUG"][
"KG"] = 14.59390;
104 convert[
"KG"][
"SLUG"] = 1.0/convert[
"SLUG"][
"KG"];
106 convert[
"SLUG*FT2"][
"KG*M2"] = 1.35594;
107 convert[
"KG*M2"][
"SLUG*FT2"] = 1.0/convert[
"SLUG*FT2"][
"KG*M2"];
109 convert[
"RAD"][
"DEG"] = 180.0/M_PI;
110 convert[
"DEG"][
"RAD"] = 1.0/convert[
"RAD"][
"DEG"];
112 convert[
"RAD/SEC"][
"DEG/SEC"] = convert[
"RAD"][
"DEG"];
113 convert[
"DEG/SEC"][
"RAD/SEC"] = 1.0/convert[
"RAD/SEC"][
"DEG/SEC"];
115 convert[
"LBS/FT"][
"N/M"] = 14.5939;
116 convert[
"N/M"][
"LBS/FT"] = 1.0/convert[
"LBS/FT"][
"N/M"];
118 convert[
"LBS/FT/SEC"][
"N/M/SEC"] = 14.5939;
119 convert[
"N/M/SEC"][
"LBS/FT/SEC"] = 1.0/convert[
"LBS/FT/SEC"][
"N/M/SEC"];
121 convert[
"LBS/FT2/SEC2"][
"N/M2/SEC2"] = 47.880259;
122 convert[
"N/M2/SEC2"][
"LBS/FT2/SEC2"] = 1.0/convert[
"LBS/FT2/SEC2"][
"N/M2/SEC2"];
124 convert[
"WATTS"][
"HP"] = 0.001341022;
125 convert[
"HP"][
"WATTS"] = 1.0/convert[
"WATTS"][
"HP"];
127 convert[
"N"][
"LBS"] = 0.22482;
128 convert[
"LBS"][
"N"] = 1.0/convert[
"N"][
"LBS"];
130 convert[
"KTS"][
"FT/SEC"] = 1.6878098571;
131 convert[
"FT/SEC"][
"KTS"] = 1.0/convert[
"KTS"][
"FT/SEC"];
132 convert[
"M/S"][
"FT/S"] = 3.2808399;
133 convert[
"M/S"][
"KTS"] = convert[
"M/S"][
"FT/S"]/convert[
"KTS"][
"FT/SEC"];
134 convert[
"M/SEC"][
"FT/SEC"] = 3.2808399;
135 convert[
"FT/S"][
"M/S"] = 1.0/convert[
"M/S"][
"FT/S"];
136 convert[
"M/SEC"][
"FT/SEC"] = 3.2808399;
137 convert[
"FT/SEC"][
"M/SEC"] = 1.0/convert[
"M/SEC"][
"FT/SEC"];
138 convert[
"KM/SEC"][
"FT/SEC"] = 3280.8399;
139 convert[
"FT/SEC"][
"KM/SEC"] = 1.0/convert[
"KM/SEC"][
"FT/SEC"];
141 convert[
"FT*LBS"][
"N*M"] = 1.35581795;
142 convert[
"N*M"][
"FT*LBS"] = 1/convert[
"FT*LBS"][
"N*M"];
144 convert[
"M4*SEC/KG"][
"FT4*SEC/SLUG"] = convert[
"M"][
"FT"]*convert[
"M"][
"FT"]*
145 convert[
"M"][
"FT"]*convert[
"M"][
"FT"]/convert[
"KG"][
"SLUG"];
146 convert[
"FT4*SEC/SLUG"][
"M4*SEC/KG"] =
147 1.0/convert[
"M4*SEC/KG"][
"FT4*SEC/SLUG"];
149 convert[
"INHG"][
"PSF"] = 70.7180803;
150 convert[
"PSF"][
"INHG"] = 1.0/convert[
"INHG"][
"PSF"];
151 convert[
"ATM"][
"INHG"] = 29.9246899;
152 convert[
"INHG"][
"ATM"] = 1.0/convert[
"ATM"][
"INHG"];
153 convert[
"PSI"][
"INHG"] = 2.03625437;
154 convert[
"INHG"][
"PSI"] = 1.0/convert[
"PSI"][
"INHG"];
155 convert[
"INHG"][
"PA"] = 3386.0;
156 convert[
"PA"][
"INHG"] = 1.0/convert[
"INHG"][
"PA"];
157 convert[
"LBS/FT2"][
"N/M2"] = 14.5939/convert[
"FT"][
"M"];
158 convert[
"N/M2"][
"LBS/FT2"] = 1.0/convert[
"LBS/FT2"][
"N/M2"];
159 convert[
"LBS/FT2"][
"PA"] = convert[
"LBS/FT2"][
"N/M2"];
160 convert[
"PA"][
"LBS/FT2"] = 1.0/convert[
"LBS/FT2"][
"PA"];
162 convert[
"KG/MIN"][
"LBS/MIN"] = convert[
"KG"][
"LBS"];
163 convert[
"KG/SEC"][
"LBS/SEC"] = convert[
"KG"][
"LBS"];
164 convert [
"N/SEC"][
"LBS/SEC"] = 0.224808943;
165 convert [
"LBS/SEC"][
"N/SEC"] = 1.0/convert [
"N/SEC"][
"LBS/SEC"];
167 convert[
"LBS/HP*HR"][
"KG/KW*HR"] = 0.6083;
168 convert[
"KG/KW*HR"][
"LBS/HP*HR"] = 1.0/convert[
"LBS/HP*HR"][
"KG/KW*HR"];
170 convert[
"KG/L"][
"LBS/GAL"] = 8.3454045;
171 convert[
"LBS/GAL"][
"KG/L"] = 1.0/convert[
"KG/L"][
"LBS/GAL"];
173 convert[
"FT3/SEC2"][
"M3/SEC2"] = convert[
"FT3"][
"M3"];
174 convert[
"M3/SEC2"][
"FT3/SEC2"] = convert[
"M3"][
"FT3"];
177 convert[
"M"][
"M"] = 1.00;
178 convert[
"KM"][
"KM"] = 1.00;
179 convert[
"FT"][
"FT"] = 1.00;
180 convert[
"IN"][
"IN"] = 1.00;
182 convert[
"M2"][
"M2"] = 1.00;
183 convert[
"FT2"][
"FT2"] = 1.00;
185 convert[
"IN3"][
"IN3"] = 1.00;
186 convert[
"CC"][
"CC"] = 1.0;
187 convert[
"M3"][
"M3"] = 1.0;
188 convert[
"FT3"][
"FT3"] = 1.0;
189 convert[
"LTR"][
"LTR"] = 1.0;
190 convert[
"GAL"][
"GAL"] = 1.0;
192 convert[
"KG"][
"KG"] = 1.00;
193 convert[
"LBS"][
"LBS"] = 1.00;
195 convert[
"KG*M2"][
"KG*M2"] = 1.00;
196 convert[
"SLUG*FT2"][
"SLUG*FT2"] = 1.00;
198 convert[
"DEG"][
"DEG"] = 1.00;
199 convert[
"RAD"][
"RAD"] = 1.00;
201 convert[
"DEG/SEC"][
"DEG/SEC"] = 1.00;
202 convert[
"RAD/SEC"][
"RAD/SEC"] = 1.00;
204 convert[
"LBS/FT"][
"LBS/FT"] = 1.00;
205 convert[
"N/M"][
"N/M"] = 1.00;
207 convert[
"LBS/FT/SEC"][
"LBS/FT/SEC"] = 1.00;
208 convert[
"N/M/SEC"][
"N/M/SEC"] = 1.00;
210 convert[
"LBS/FT2/SEC2"][
"LBS/FT2/SEC2"] = 1.00;
211 convert[
"N/M2/SEC2"][
"N/M2/SEC2"] = 1.00;
213 convert[
"HP"][
"HP"] = 1.00;
214 convert[
"WATTS"][
"WATTS"] = 1.00;
216 convert[
"N"][
"N"] = 1.00;
218 convert[
"FT/SEC"][
"FT/SEC"] = 1.00;
219 convert[
"KTS"][
"KTS"] = 1.00;
220 convert[
"M/S"][
"M/S"] = 1.0;
221 convert[
"M/SEC"][
"M/SEC"] = 1.0;
222 convert[
"KM/SEC"][
"KM/SEC"] = 1.0;
224 convert[
"FT*LBS"][
"FT*LBS"] = 1.00;
225 convert[
"N*M"][
"N*M"] = 1.00;
227 convert[
"M4*SEC/KG"][
"M4*SEC/KG"] = 1.0;
228 convert[
"FT4*SEC/SLUG"][
"FT4*SEC/SLUG"] = 1.0;
230 convert[
"PSI"][
"PSI"] = 1.00;
231 convert[
"PSF"][
"PSF"] = 1.00;
232 convert[
"INHG"][
"INHG"] = 1.00;
233 convert[
"ATM"][
"ATM"] = 1.0;
234 convert[
"PA"][
"PA"] = 1.0;
235 convert[
"N/M2"][
"N/M2"] = 1.00;
236 convert[
"LBS/FT2"][
"LBS/FT2"] = 1.00;
238 convert[
"LBS/SEC"][
"LBS/SEC"] = 1.00;
239 convert[
"KG/MIN"][
"KG/MIN"] = 1.0;
240 convert[
"LBS/MIN"][
"LBS/MIN"] = 1.0;
241 convert[
"N/SEC"][
"N/SEC"] = 1.0;
243 convert[
"LBS/HP*HR"][
"LBS/HP*HR"] = 1.0;
244 convert[
"KG/KW*HR"][
"KG/KW*HR"] = 1.0;
246 convert[
"KG/L"][
"KG/L"] = 1.0;
247 convert[
"LBS/GAL"][
"LBS/GAL"] = 1.0;
249 convert[
"FT3/SEC2"][
"FT3/SEC2"] = 1.0;
250 convert[
"M3/SEC2"][
"M3/SEC2"] = 1.0;
252 convert[
"VOLTS"][
"VOLTS"] = 1.0;
253 convert[
"OHMS"][
"OHMS"] = 1.0;
254 convert[
"AMPERES"][
"AMPERES"] = 1.0;
262 for (
unsigned int i = 0; i < children.size(); ++i)
280 attributes[key] = value;
291 if (attribute.empty()) {
293 err <<
"Expecting numeric attribute value, but got no data\n";
299 number = atof_locale_c(attribute);
302 err << e.what() <<
"\n";
314 if (children.size() > el) {
328 if (children.size() > element_index+1) {
330 return children[element_index];
341 if (!data_lines.empty())
return data_lines[i];
342 else return string(
"");
349 if (data_lines.size() == 1) {
352 number = atof_locale_c(data_lines[0]);
355 err << e.what() <<
"\n";
360 }
else if (data_lines.empty()) {
362 err <<
"Expected numeric value, but got no data\n";
366 err <<
"Attempting to get single data value in element "
367 <<
"<" << name <<
">\n"
368 <<
" from multiple lines:\n";
369 for(
unsigned int i=0; i<data_lines.size(); ++i)
370 err << data_lines[i] <<
"\n";
379 unsigned int number_of_elements=0;
382 number_of_elements++;
385 return number_of_elements;
392 if (el.empty() && children.size() >= 1) {
396 for (
unsigned int i=0; i<children.size(); i++) {
397 if (el == children[i]->
GetName()) {
411 if (element_index < children.size()) {
412 return children[element_index++];
418 for (
unsigned int i=element_index; i<children.size(); i++) {
419 if (el == children[i]->
GetName()) {
435 value = DisperseValue(element, value);
439 err <<
"Attempting to get non-existent element " << el <<
"\n";
461 log <<
"Attempting to get non-existent element " << el
462 <<
" ;returning false\n";
487 err <<
"Attempting to get non-existent element " << el <<
"\n";
493 if (!supplied_units.empty()) {
494 if (convert.find(supplied_units) == convert.end()) {
496 err <<
"Supplied unit: \"" << supplied_units <<
"\" does not exist (typo?).\n";
499 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
501 err <<
"Supplied unit: \"" << supplied_units
502 <<
"\" cannot be converted to " << target_units <<
"\n";
510 if ((supplied_units ==
"RAD") && (fabs(value) > 2 * M_PI)) {
512 log << element->
GetName() <<
" value "
513 << value <<
" RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]\n";
515 if ((supplied_units ==
"DEG") && (fabs(value) > 360.0)) {
517 log << element->
GetName() <<
" value "
518 << value <<
" DEG is outside the range [ -360 DEG ; +360 DEG ]\n";
522 if (!supplied_units.empty()) {
523 value *= convert[supplied_units][target_units];
526 if ((target_units ==
"RAD") && (fabs(value) > 2 * M_PI)) {
528 log << element->
GetName() <<
" value "
529 << value <<
" RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]\n";
531 if ((target_units ==
"DEG") && (fabs(value) > 360.0)) {
533 log << element->
GetName() <<
" value "
534 << value <<
" DEG is outside the range [ -360 DEG ; +360 DEG ]\n";
537 value = DisperseValue(element, value, supplied_units, target_units);
545 const string& supplied_units,
546 const string& target_units)
552 err <<
"Attempting to get non-existent element " << el <<
"\n";
556 if (!supplied_units.empty()) {
557 if (convert.find(supplied_units) == convert.end()) {
559 err <<
"Supplied unit: \"" << supplied_units
560 <<
"\" does not exist (typo?).\n";
563 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
565 err <<
"Supplied unit: \"" << supplied_units
566 <<
"\" cannot be converted to " << target_units <<
"\n";
572 if (!supplied_units.empty()) {
573 value *= convert[supplied_units][target_units];
576 value = DisperseValue(element, value, supplied_units, target_units);
590 if (!supplied_units.empty()) {
591 if (convert.find(supplied_units) == convert.end()) {
593 err <<
"Supplied unit: \"" << supplied_units
594 <<
"\" does not exist (typo?).\n";
597 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
599 err <<
"Supplied unit: \"" << supplied_units
600 <<
"\" cannot be converted to " << target_units <<
"\n";
609 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
610 triplet(1) = DisperseValue(item, value, supplied_units, target_units);
620 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
621 triplet(2) = DisperseValue(item, value, supplied_units, target_units);
630 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
631 triplet(3) = DisperseValue(item, value, supplied_units, target_units);
641double Element::DisperseValue(
Element *e,
double val,
const std::string& supplied_units,
642 const std::string& target_units)
645 bool disperse =
false;
647 if(
char* num = getenv(
"JSBSIM_DISPERSE"); num !=
nullptr)
648 disperse = strtol(num,
nullptr, 0) == 1;
652 if (!supplied_units.empty()) disp *= convert[supplied_units][target_units];
656 if (attType ==
"gaussian" || attType ==
"gaussiansigned") {
658 if (attType ==
"gaussian")
659 value = val + disp*grn;
661 value = (val + disp*grn)*FGJSBBase::sign(grn);
662 }
else if (attType ==
"uniform" || attType ==
"uniformsigned") {
664 if (attType ==
"uniform")
665 value = val + disp * urn;
667 value = (val + disp * urn)*FGJSBBase::sign(urn);
669 XMLLogException err(
this);
670 err <<
"Unknown dispersion type" << attType <<
"\n";
686 for (
unsigned int spaces=0; spaces<=level; spaces++) out <<
" ";
687 out <<
"Element Name: " << name;
689 for (
auto const& attr : attributes)
690 out <<
" " << attr.first <<
" = " << attr.second;
693 for (
unsigned i=0; i<data_lines.size(); i++) {
694 for (
unsigned int spaces=0; spaces<=level; spaces++) out <<
" ";
695 out << data_lines[i] << endl;
699 for (
unsigned int i=0; i<children.size(); i++) {
700 children[i]->Print(level);
708 attributes[name] = value;
715 string::size_type string_start = d.find_first_not_of(
" \t");
716 if (string_start != string::npos && string_start > 0) {
717 d.erase(0,string_start);
719 data_lines.push_back(d);
726 ostringstream message;
732 return message.str();
739 map<string, string>::iterator it;
741 for (it=el->attributes.begin(); it != el->attributes.end(); ++it) {
742 if (attributes.find(it->first) == attributes.end())
743 attributes[it->first] = it->second;
745 if (FGJSBBase::debug_lvl > 0 && (attributes[it->first] != it->second)) {
747 log <<
" Attribute '" << it->first <<
"' is overridden in file "
749 <<
" The value '" << attributes[it->first] <<
"' will be used instead of '"
750 << it->second <<
"'.\n";
Element * FindElement(const std::string &el="")
Searches for a specified element.
const std::string & GetName(void) const
Retrieves the element name.
bool SetAttributeValue(const std::string &key, const std::string &value)
Modifies an attribute.
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
FGColumnVector3 FindElementTripletConvertTo(const std::string &target_units)
Composes a 3-element column vector for the supplied location or orientation.
Element * GetElement(unsigned int el=0)
Returns a pointer to the element requested by index.
Element(const std::string &nm)
Constructor.
bool FindElementValueAsBoolean(const std::string &el="")
Searches for the named element and returns the data belonging to it as a bool.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
int GetLineNumber(void) const
Returns the line number at which the element has been defined.
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to an element.
const std::string & GetFileName(void) const
Returns the name of the file in which the element has been read.
unsigned int GetNumElements(void)
Returns the number of child elements for this element.
void MergeAttributes(Element *el)
Merges the attributes of the current element with another element.
void AddAttribute(const std::string &name, const std::string &value)
Stores an attribute belonging to this element.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
std::string FindElementValue(const std::string &el="")
Searches for the named element and returns the string data belonging to it.
void Print(unsigned int level=0)
Prints the element.
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.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
double GetDataAsNumber(void)
Converts the element data to a number.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
void SetParent(Element *p)
This function sets the value of the parent class attribute to the supplied Element pointer.
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 FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
void AddData(std::string d)
Stores data belonging to this element.
~Element(void)
Destructor.
This class implements a 3 element column vector.
double GetNormalRandomNumber(void)
Get a random number which probability of occurrence is following Gauss normal distribution with a mea...
double GetUniformRandomNumber(void)
Get a random number which probability of occurrence is uniformly distributed over the segment [-1;1(.
Main namespace for the JSBSim Flight Dynamics Model.