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"];
105 convert[
"SLUG"][
"LBS"] = convert[
"SLUG"][
"KG"]/convert[
"LBS"][
"KG"];
106 convert[
"LBS"][
"SLUG"] = 1.0/convert[
"SLUG"][
"LBS"];
108 convert[
"SLUG*FT2"][
"KG*M2"] = 1.35594;
109 convert[
"KG*M2"][
"SLUG*FT2"] = 1.0/convert[
"SLUG*FT2"][
"KG*M2"];
111 convert[
"RAD"][
"DEG"] = 180.0/M_PI;
112 convert[
"DEG"][
"RAD"] = 1.0/convert[
"RAD"][
"DEG"];
114 convert[
"RAD/SEC"][
"DEG/SEC"] = convert[
"RAD"][
"DEG"];
115 convert[
"DEG/SEC"][
"RAD/SEC"] = 1.0/convert[
"RAD/SEC"][
"DEG/SEC"];
117 convert[
"LBS/FT"][
"N/M"] = 14.5939;
118 convert[
"N/M"][
"LBS/FT"] = 1.0/convert[
"LBS/FT"][
"N/M"];
120 convert[
"LBS/FT/SEC"][
"N/M/SEC"] = 14.5939;
121 convert[
"N/M/SEC"][
"LBS/FT/SEC"] = 1.0/convert[
"LBS/FT/SEC"][
"N/M/SEC"];
123 convert[
"LBS/FT2/SEC2"][
"N/M2/SEC2"] = 47.880259;
124 convert[
"N/M2/SEC2"][
"LBS/FT2/SEC2"] = 1.0/convert[
"LBS/FT2/SEC2"][
"N/M2/SEC2"];
126 convert[
"WATTS"][
"HP"] = 0.001341022;
127 convert[
"HP"][
"WATTS"] = 1.0/convert[
"WATTS"][
"HP"];
129 convert[
"N"][
"LBS"] = 0.22482;
130 convert[
"LBS"][
"N"] = 1.0/convert[
"N"][
"LBS"];
132 convert[
"KTS"][
"FT/SEC"] = 1.6878098571;
133 convert[
"FT/SEC"][
"KTS"] = 1.0/convert[
"KTS"][
"FT/SEC"];
134 convert[
"M/S"][
"FT/S"] = 3.2808399;
135 convert[
"M/S"][
"KTS"] = convert[
"M/S"][
"FT/S"]/convert[
"KTS"][
"FT/SEC"];
136 convert[
"M/SEC"][
"FT/SEC"] = 3.2808399;
137 convert[
"FT/S"][
"M/S"] = 1.0/convert[
"M/S"][
"FT/S"];
138 convert[
"M/SEC"][
"FT/SEC"] = 3.2808399;
139 convert[
"FT/SEC"][
"M/SEC"] = 1.0/convert[
"M/SEC"][
"FT/SEC"];
140 convert[
"KM/SEC"][
"FT/SEC"] = 3280.8399;
141 convert[
"FT/SEC"][
"KM/SEC"] = 1.0/convert[
"KM/SEC"][
"FT/SEC"];
143 convert[
"FT*LBS"][
"N*M"] = 1.35581795;
144 convert[
"N*M"][
"FT*LBS"] = 1/convert[
"FT*LBS"][
"N*M"];
146 convert[
"M4*SEC/KG"][
"FT4*SEC/SLUG"] = convert[
"M"][
"FT"]*convert[
"M"][
"FT"]*
147 convert[
"M"][
"FT"]*convert[
"M"][
"FT"]/convert[
"KG"][
"SLUG"];
148 convert[
"FT4*SEC/SLUG"][
"M4*SEC/KG"] =
149 1.0/convert[
"M4*SEC/KG"][
"FT4*SEC/SLUG"];
151 convert[
"INHG"][
"PSF"] = 70.7180803;
152 convert[
"PSF"][
"INHG"] = 1.0/convert[
"INHG"][
"PSF"];
153 convert[
"ATM"][
"INHG"] = 29.9246899;
154 convert[
"INHG"][
"ATM"] = 1.0/convert[
"ATM"][
"INHG"];
155 convert[
"PSI"][
"INHG"] = 2.03625437;
156 convert[
"INHG"][
"PSI"] = 1.0/convert[
"PSI"][
"INHG"];
157 convert[
"INHG"][
"PA"] = 3386.0;
158 convert[
"PA"][
"INHG"] = 1.0/convert[
"INHG"][
"PA"];
159 convert[
"LBS/FT2"][
"N/M2"] = 14.5939/convert[
"FT"][
"M"];
160 convert[
"N/M2"][
"LBS/FT2"] = 1.0/convert[
"LBS/FT2"][
"N/M2"];
161 convert[
"LBS/FT2"][
"PA"] = convert[
"LBS/FT2"][
"N/M2"];
162 convert[
"PA"][
"LBS/FT2"] = 1.0/convert[
"LBS/FT2"][
"PA"];
164 convert[
"KG/MIN"][
"LBS/MIN"] = convert[
"KG"][
"LBS"];
165 convert[
"KG/SEC"][
"LBS/SEC"] = convert[
"KG"][
"LBS"];
166 convert [
"N/SEC"][
"LBS/SEC"] = 0.224808943;
167 convert [
"LBS/SEC"][
"N/SEC"] = 1.0/convert [
"N/SEC"][
"LBS/SEC"];
169 convert[
"LBS/HP*HR"][
"KG/KW*HR"] = 0.6083;
170 convert[
"KG/KW*HR"][
"LBS/HP*HR"] = 1.0/convert[
"LBS/HP*HR"][
"KG/KW*HR"];
172 convert[
"KG/L"][
"LBS/GAL"] = 8.3454045;
173 convert[
"LBS/GAL"][
"KG/L"] = 1.0/convert[
"KG/L"][
"LBS/GAL"];
175 convert[
"FT3/SEC2"][
"M3/SEC2"] = convert[
"FT3"][
"M3"];
176 convert[
"M3/SEC2"][
"FT3/SEC2"] = convert[
"M3"][
"FT3"];
179 convert[
"M"][
"M"] = 1.00;
180 convert[
"KM"][
"KM"] = 1.00;
181 convert[
"FT"][
"FT"] = 1.00;
182 convert[
"IN"][
"IN"] = 1.00;
184 convert[
"M2"][
"M2"] = 1.00;
185 convert[
"FT2"][
"FT2"] = 1.00;
187 convert[
"IN3"][
"IN3"] = 1.00;
188 convert[
"CC"][
"CC"] = 1.0;
189 convert[
"M3"][
"M3"] = 1.0;
190 convert[
"FT3"][
"FT3"] = 1.0;
191 convert[
"LTR"][
"LTR"] = 1.0;
192 convert[
"GAL"][
"GAL"] = 1.0;
194 convert[
"KG"][
"KG"] = 1.00;
195 convert[
"LBS"][
"LBS"] = 1.00;
197 convert[
"KG*M2"][
"KG*M2"] = 1.00;
198 convert[
"SLUG*FT2"][
"SLUG*FT2"] = 1.00;
200 convert[
"DEG"][
"DEG"] = 1.00;
201 convert[
"RAD"][
"RAD"] = 1.00;
203 convert[
"DEG/SEC"][
"DEG/SEC"] = 1.00;
204 convert[
"RAD/SEC"][
"RAD/SEC"] = 1.00;
206 convert[
"LBS/FT"][
"LBS/FT"] = 1.00;
207 convert[
"N/M"][
"N/M"] = 1.00;
209 convert[
"LBS/FT/SEC"][
"LBS/FT/SEC"] = 1.00;
210 convert[
"N/M/SEC"][
"N/M/SEC"] = 1.00;
212 convert[
"LBS/FT2/SEC2"][
"LBS/FT2/SEC2"] = 1.00;
213 convert[
"N/M2/SEC2"][
"N/M2/SEC2"] = 1.00;
215 convert[
"HP"][
"HP"] = 1.00;
216 convert[
"WATTS"][
"WATTS"] = 1.00;
218 convert[
"N"][
"N"] = 1.00;
220 convert[
"FT/SEC"][
"FT/SEC"] = 1.00;
221 convert[
"KTS"][
"KTS"] = 1.00;
222 convert[
"M/S"][
"M/S"] = 1.0;
223 convert[
"M/SEC"][
"M/SEC"] = 1.0;
224 convert[
"KM/SEC"][
"KM/SEC"] = 1.0;
226 convert[
"FT*LBS"][
"FT*LBS"] = 1.00;
227 convert[
"N*M"][
"N*M"] = 1.00;
229 convert[
"M4*SEC/KG"][
"M4*SEC/KG"] = 1.0;
230 convert[
"FT4*SEC/SLUG"][
"FT4*SEC/SLUG"] = 1.0;
232 convert[
"PSI"][
"PSI"] = 1.00;
233 convert[
"PSF"][
"PSF"] = 1.00;
234 convert[
"INHG"][
"INHG"] = 1.00;
235 convert[
"ATM"][
"ATM"] = 1.0;
236 convert[
"PA"][
"PA"] = 1.0;
237 convert[
"N/M2"][
"N/M2"] = 1.00;
238 convert[
"LBS/FT2"][
"LBS/FT2"] = 1.00;
240 convert[
"LBS/SEC"][
"LBS/SEC"] = 1.00;
241 convert[
"KG/MIN"][
"KG/MIN"] = 1.0;
242 convert[
"LBS/MIN"][
"LBS/MIN"] = 1.0;
243 convert[
"N/SEC"][
"N/SEC"] = 1.0;
245 convert[
"LBS/HP*HR"][
"LBS/HP*HR"] = 1.0;
246 convert[
"KG/KW*HR"][
"KG/KW*HR"] = 1.0;
248 convert[
"KG/L"][
"KG/L"] = 1.0;
249 convert[
"LBS/GAL"][
"LBS/GAL"] = 1.0;
251 convert[
"FT3/SEC2"][
"FT3/SEC2"] = 1.0;
252 convert[
"M3/SEC2"][
"M3/SEC2"] = 1.0;
254 convert[
"VOLTS"][
"VOLTS"] = 1.0;
255 convert[
"OHMS"][
"OHMS"] = 1.0;
256 convert[
"AMPERES"][
"AMPERES"] = 1.0;
264 for (
unsigned int i = 0; i < children.size(); ++i)
282 attributes[key] = value;
293 if (attribute.empty()) {
295 err <<
"Expecting numeric attribute value, but got no data\n";
301 number = atof_locale_c(attribute);
304 err << e.what() <<
"\n";
316 if (children.size() > el) {
330 if (children.size() > element_index+1) {
332 return children[element_index];
343 if (!data_lines.empty())
return data_lines[i];
344 else return string(
"");
351 if (data_lines.size() == 1) {
354 number = atof_locale_c(data_lines[0]);
357 err << e.what() <<
"\n";
362 }
else if (data_lines.empty()) {
364 err <<
"Expected numeric value, but got no data\n";
368 err <<
"Attempting to get single data value in element "
369 <<
"<" << name <<
">\n"
370 <<
" from multiple lines:\n";
371 for(
unsigned int i=0; i<data_lines.size(); ++i)
372 err << data_lines[i] <<
"\n";
381 unsigned int number_of_elements=0;
384 number_of_elements++;
387 return number_of_elements;
394 if (el.empty() && children.size() >= 1) {
398 for (
unsigned int i=0; i<children.size(); i++) {
399 if (el == children[i]->
GetName()) {
413 if (element_index < children.size()) {
414 return children[element_index++];
420 for (
unsigned int i=element_index; i<children.size(); i++) {
421 if (el == children[i]->
GetName()) {
437 value = DisperseValue(element, value);
441 err <<
"Attempting to get non-existent element " << el <<
"\n";
463 log <<
"Attempting to get non-existent element " << el
464 <<
" ;returning false\n";
489 err <<
"Attempting to get non-existent element " << el <<
"\n";
495 if (!supplied_units.empty()) {
496 if (convert.find(supplied_units) == convert.end()) {
498 err <<
"Supplied unit: \"" << supplied_units <<
"\" does not exist (typo?).\n";
501 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
503 err <<
"Supplied unit: \"" << supplied_units
504 <<
"\" cannot be converted to " << target_units <<
"\n";
512 if ((supplied_units ==
"RAD") && (fabs(value) > 2 * M_PI)) {
514 log << element->
GetName() <<
" value "
515 << value <<
" RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]\n";
517 if ((supplied_units ==
"DEG") && (fabs(value) > 360.0)) {
519 log << element->
GetName() <<
" value "
520 << value <<
" DEG is outside the range [ -360 DEG ; +360 DEG ]\n";
524 if (!supplied_units.empty()) {
525 value *= convert[supplied_units][target_units];
528 if ((target_units ==
"RAD") && (fabs(value) > 2 * M_PI)) {
530 log << element->
GetName() <<
" value "
531 << value <<
" RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]\n";
533 if ((target_units ==
"DEG") && (fabs(value) > 360.0)) {
535 log << element->
GetName() <<
" value "
536 << value <<
" DEG is outside the range [ -360 DEG ; +360 DEG ]\n";
539 value = DisperseValue(element, value, supplied_units, target_units);
547 const string& supplied_units,
548 const string& target_units)
554 err <<
"Attempting to get non-existent element " << el <<
"\n";
558 if (!supplied_units.empty()) {
559 if (convert.find(supplied_units) == convert.end()) {
561 err <<
"Supplied unit: \"" << supplied_units
562 <<
"\" does not exist (typo?).\n";
565 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
567 err <<
"Supplied unit: \"" << supplied_units
568 <<
"\" cannot be converted to " << target_units <<
"\n";
574 if (!supplied_units.empty()) {
575 value *= convert[supplied_units][target_units];
578 value = DisperseValue(element, value, supplied_units, target_units);
592 if (!supplied_units.empty()) {
593 if (convert.find(supplied_units) == convert.end()) {
595 err <<
"Supplied unit: \"" << supplied_units
596 <<
"\" does not exist (typo?).\n";
599 if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
601 err <<
"Supplied unit: \"" << supplied_units
602 <<
"\" cannot be converted to " << target_units <<
"\n";
611 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
612 triplet(1) = DisperseValue(item, value, supplied_units, target_units);
622 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
623 triplet(2) = DisperseValue(item, value, supplied_units, target_units);
632 if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
633 triplet(3) = DisperseValue(item, value, supplied_units, target_units);
643double Element::DisperseValue(
Element *e,
double val,
const std::string& supplied_units,
644 const std::string& target_units)
647 bool disperse =
false;
649 if(
char* num = getenv(
"JSBSIM_DISPERSE"); num !=
nullptr)
650 disperse = strtol(num,
nullptr, 0) == 1;
654 if (!supplied_units.empty()) disp *= convert[supplied_units][target_units];
658 if (attType ==
"gaussian" || attType ==
"gaussiansigned") {
660 if (attType ==
"gaussian")
661 value = val + disp*grn;
663 value = (val + disp*grn)*FGJSBBase::sign(grn);
664 }
else if (attType ==
"uniform" || attType ==
"uniformsigned") {
666 if (attType ==
"uniform")
667 value = val + disp * urn;
669 value = (val + disp * urn)*FGJSBBase::sign(urn);
671 XMLLogException err(
this);
672 err <<
"Unknown dispersion type" << attType <<
"\n";
688 for (
unsigned int spaces=0; spaces<=level; spaces++) out <<
" ";
689 out <<
"Element Name: " << name;
691 for (
auto const& attr : attributes)
692 out <<
" " << attr.first <<
" = " << attr.second;
695 for (
unsigned i=0; i<data_lines.size(); i++) {
696 for (
unsigned int spaces=0; spaces<=level; spaces++) out <<
" ";
697 out << data_lines[i] << endl;
701 for (
unsigned int i=0; i<children.size(); i++) {
702 children[i]->Print(level);
710 attributes[name] = value;
717 string::size_type string_start = d.find_first_not_of(
" \t");
718 if (string_start != string::npos && string_start > 0) {
719 d.erase(0,string_start);
721 data_lines.push_back(d);
728 ostringstream message;
734 return message.str();
741 map<string, string>::iterator it;
743 for (it=el->attributes.begin(); it != el->attributes.end(); ++it) {
744 if (attributes.find(it->first) == attributes.end())
745 attributes[it->first] = it->second;
747 if (FGJSBBase::debug_lvl > 0 && (attributes[it->first] != it->second)) {
749 log <<
" Attribute '" << it->first <<
"' is overridden in file "
751 <<
" The value '" << attributes[it->first] <<
"' will be used instead of '"
752 << 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.