1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Author:       Jon Berndt
4  Date started: 09/28/2004
5  Purpose:      XML element class
6  Called by:    FGXMLParse
7 
8  ------------- Copyright (C) 2001  Jon S. Berndt (jon@jsbsim.org) -------------
9 
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
12  Software Foundation; either version 2 of the License, or (at your option) any
13  later version.
14 
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
18  details.
19 
20  You should have received a copy of the GNU Lesser General Public License along
21  with this program; if not, write to the Free Software Foundation, Inc., 59
22  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24  Further information about the GNU Lesser General Public License can also be
25  found on the world wide web at http://www.gnu.org.
26 
27 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28 INCLUDES
29 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
30 
31 #include "FGXMLElement.h"
32 #include "FGJSBBase.h"
33 
34 using namespace std;
35 
36 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
37 FORWARD DECLARATIONS
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
39 
40 namespace JSBSim {
41 
42 bool Element::converterIsInitialized = false;
43 map <string, map <string, double> > Element::convert;
44 
45 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
46 CLASS IMPLEMENTATION
47 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
48 
Element(const string & nm)49 Element::Element(const string& nm)
50 {
51   name   = nm;
52   parent = 0L;
53   element_index = 0;
54   line_number = -1;
55 
56   if (!converterIsInitialized) {
57     converterIsInitialized = true;
58     // convert ["from"]["to"] = factor, so: from * factor = to
59     // Length
60     convert["M"]["FT"] = 3.2808399;
61     convert["FT"]["M"] = 1.0/convert["M"]["FT"];
62     convert["CM"]["FT"] = 0.032808399;
63     convert["FT"]["CM"] = 1.0/convert["CM"]["FT"];
64     convert["KM"]["FT"] = 3280.8399;
65     convert["FT"]["KM"] = 1.0/convert["KM"]["FT"];
66     convert["FT"]["IN"] = 12.0;
67     convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
68     convert["IN"]["M"] = convert["IN"]["FT"] * convert["FT"]["M"];
69     convert["M"]["IN"] = convert["M"]["FT"] * convert["FT"]["IN"];
70     // Area
71     convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
72     convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
73     convert["CM2"]["FT2"] = convert["CM"]["FT"]*convert["CM"]["FT"];
74     convert["FT2"]["CM2"] = 1.0/convert["CM2"]["FT2"];
75     convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
76     convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
77     convert["FT2"]["IN2"] = 144.0;
78     convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
79     // Volume
80     convert["IN3"]["CC"] = 16.387064;
81     convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
82     convert["FT3"]["IN3"] = 1728.0;
83     convert["IN3"]["FT3"] = 1.0/convert["FT3"]["IN3"];
84     convert["M3"]["FT3"] = 35.3146667;
85     convert["FT3"]["M3"] = 1.0/convert["M3"]["FT3"];
86     convert["LTR"]["IN3"] = 61.0237441;
87     convert["IN3"]["LTR"] = 1.0/convert["LTR"]["IN3"];
88     convert["GAL"]["FT3"] = 0.133681;
89     convert["FT3"]["GAL"] = 1.0/convert["GAL"]["FT3"];
90     convert["IN3"]["GAL"] = convert["IN3"]["FT3"]*convert["FT3"]["GAL"];
91     convert["LTR"]["GAL"] = convert["LTR"]["IN3"]*convert["IN3"]["GAL"];
92     convert["M3"]["GAL"] = 1000.*convert["LTR"]["GAL"];
93     convert["CC"]["GAL"] = convert["CC"]["IN3"]*convert["IN3"]["GAL"];
94     // Mass & Weight
95     convert["LBS"]["KG"] = 0.45359237;
96     convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
97     convert["SLUG"]["KG"] = 14.59390;
98     convert["KG"]["SLUG"] = 1.0/convert["SLUG"]["KG"];
99     // Moments of Inertia
100     convert["SLUG*FT2"]["KG*M2"] = 1.35594;
101     convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
102     // Angles
103     convert["RAD"]["DEG"] = 180.0/M_PI;
104     convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
105     // Angular rates
106     convert["RAD/SEC"]["DEG/SEC"] = convert["RAD"]["DEG"];
107     convert["DEG/SEC"]["RAD/SEC"] = 1.0/convert["RAD/SEC"]["DEG/SEC"];
108     // Spring force
109     convert["LBS/FT"]["N/M"] = 14.5939;
110     convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
111     // Damping force
112     convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
113     convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
114     // Damping force (Square Law)
115     convert["LBS/FT2/SEC2"]["N/M2/SEC2"] = 47.880259;
116     convert["N/M2/SEC2"]["LBS/FT2/SEC2"] = 1.0/convert["LBS/FT2/SEC2"]["N/M2/SEC2"];
117     // Power
118     convert["WATTS"]["HP"] = 0.001341022;
119     convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
120     // Force
121     convert["N"]["LBS"] = 0.22482;
122     convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
123     // Velocity
124     convert["KTS"]["FT/SEC"] = 1.68781;
125     convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
126     convert["M/S"]["FT/S"] = 3.2808399;
127     convert["M/S"]["KTS"] = convert["M/S"]["FT/S"]/convert["KTS"]["FT/SEC"];
128     convert["M/SEC"]["FT/SEC"] = 3.2808399;
129     convert["FT/S"]["M/S"] = 1.0/convert["M/S"]["FT/S"];
130     convert["M/SEC"]["FT/SEC"] = 3.2808399;
131     convert["FT/SEC"]["M/SEC"] = 1.0/convert["M/SEC"]["FT/SEC"];
132     convert["KM/SEC"]["FT/SEC"] = 3280.8399;
133     convert["FT/SEC"]["KM/SEC"] = 1.0/convert["KM/SEC"]["FT/SEC"];
134     // Torque
135     convert["FT*LBS"]["N*M"] = 1.35581795;
136     convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
137     // Valve
138     convert["M4*SEC/KG"]["FT4*SEC/SLUG"] = convert["M"]["FT"]*convert["M"]["FT"]*
139       convert["M"]["FT"]*convert["M"]["FT"]/convert["KG"]["SLUG"];
140     convert["FT4*SEC/SLUG"]["M4*SEC/KG"] =
141       1.0/convert["M4*SEC/KG"]["FT4*SEC/SLUG"];
142     // Pressure
143     convert["INHG"]["PSF"] = 70.7180803;
144     convert["PSF"]["INHG"] = 1.0/convert["INHG"]["PSF"];
145     convert["ATM"]["INHG"] = 29.9246899;
146     convert["INHG"]["ATM"] = 1.0/convert["ATM"]["INHG"];
147     convert["PSI"]["INHG"] = 2.03625437;
148     convert["INHG"]["PSI"] = 1.0/convert["PSI"]["INHG"];
149     convert["INHG"]["PA"] = 3386.0; // inches Mercury to pascals
150     convert["PA"]["INHG"] = 1.0/convert["INHG"]["PA"];
151     convert["LBS/FT2"]["N/M2"] = 14.5939/convert["FT"]["M"];
152     convert["N/M2"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["N/M2"];
153     convert["LBS/FT2"]["PA"] = convert["LBS/FT2"]["N/M2"];
154     convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
155     // Mass flow
156     convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
157     convert ["N/SEC"]["LBS/SEC"] = 0.224808943;
158     convert ["LBS/SEC"]["N/SEC"] = 1.0/convert ["N/SEC"]["LBS/SEC"];
159     // Fuel Consumption
160     convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
161     convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
162     // Density
163     convert["KG/L"]["LBS/GAL"] = 8.3454045;
164     convert["LBS/GAL"]["KG/L"] = 1.0/convert["KG/L"]["LBS/GAL"];
165 
166     // Length
167     convert["M"]["M"] = 1.00;
168     convert["KM"]["KM"] = 1.00;
169     convert["FT"]["FT"] = 1.00;
170     convert["IN"]["IN"] = 1.00;
171     // Area
172     convert["M2"]["M2"] = 1.00;
173     convert["FT2"]["FT2"] = 1.00;
174     // Volume
175     convert["IN3"]["IN3"] = 1.00;
176     convert["CC"]["CC"] = 1.0;
177     convert["M3"]["M3"] = 1.0;
178     convert["FT3"]["FT3"] = 1.0;
179     convert["LTR"]["LTR"] = 1.0;
180     convert["GAL"]["GAL"] = 1.0;
181     // Mass & Weight
182     convert["KG"]["KG"] = 1.00;
183     convert["LBS"]["LBS"] = 1.00;
184     // Moments of Inertia
185     convert["KG*M2"]["KG*M2"] = 1.00;
186     convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
187     // Angles
188     convert["DEG"]["DEG"] = 1.00;
189     convert["RAD"]["RAD"] = 1.00;
190     // Angular rates
191     convert["DEG/SEC"]["DEG/SEC"] = 1.00;
192     convert["RAD/SEC"]["RAD/SEC"] = 1.00;
193     // Spring force
194     convert["LBS/FT"]["LBS/FT"] = 1.00;
195     convert["N/M"]["N/M"] = 1.00;
196     // Damping force
197     convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
198     convert["N/M/SEC"]["N/M/SEC"] = 1.00;
199     // Damping force (Square law)
200     convert["LBS/FT2/SEC2"]["LBS/FT2/SEC2"] = 1.00;
201     convert["N/M2/SEC2"]["N/M2/SEC2"] = 1.00;
202     // Power
203     convert["HP"]["HP"] = 1.00;
204     convert["WATTS"]["WATTS"] = 1.00;
205     // Force
206     convert["N"]["N"] = 1.00;
207     // Velocity
208     convert["FT/SEC"]["FT/SEC"] = 1.00;
209     convert["KTS"]["KTS"] = 1.00;
210     convert["M/S"]["M/S"] = 1.0;
211     convert["M/SEC"]["M/SEC"] = 1.0;
212     convert["KM/SEC"]["KM/SEC"] = 1.0;
213     // Torque
214     convert["FT*LBS"]["FT*LBS"] = 1.00;
215     convert["N*M"]["N*M"] = 1.00;
216     // Valve
217     convert["M4*SEC/KG"]["M4*SEC/KG"] = 1.0;
218     convert["FT4*SEC/SLUG"]["FT4*SEC/SLUG"] = 1.0;
219     // Pressure
220     convert["PSI"]["PSI"] = 1.00;
221     convert["PSF"]["PSF"] = 1.00;
222     convert["INHG"]["INHG"] = 1.00;
223     convert["ATM"]["ATM"] = 1.0;
224     convert["PA"]["PA"] = 1.0;
225     convert["N/M2"]["N/M2"] = 1.00;
226     convert["LBS/FT2"]["LBS/FT2"] = 1.00;
227     // Mass flow
228     convert["LBS/SEC"]["LBS/SEC"] = 1.00;
229     convert["KG/MIN"]["KG/MIN"] = 1.0;
230     convert["LBS/MIN"]["LBS/MIN"] = 1.0;
231     convert["N/SEC"]["N/SEC"] = 1.0;
232     // Fuel Consumption
233     convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
234     convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
235     // Density
236     convert["KG/L"]["KG/L"] = 1.0;
237     convert["LBS/GAL"]["LBS/GAL"] = 1.0;
238   }
239 }
240 
241 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
242 
~Element(void)243 Element::~Element(void)
244 {
245   for (unsigned int i = 0; i < children.size(); ++i)
246     children[i]->SetParent(0);
247 }
248 
249 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
250 
GetAttributeValue(const string & attr)251 string Element::GetAttributeValue(const string& attr)
252 {
253   if (HasAttribute(attr))  return attributes[attr];
254   else                     return ("");
255 }
256 
257 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
258 
SetAttributeValue(const std::string & key,const std::string & value)259 bool Element::SetAttributeValue(const std::string& key, const std::string& value)
260 {
261   bool ret = HasAttribute(key);
262   if (ret)
263     attributes[key] = value;
264 
265   return ret;
266 }
267 
268 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
269 
GetAttributeValueAsNumber(const string & attr)270 double Element::GetAttributeValueAsNumber(const string& attr)
271 {
272   string attribute = GetAttributeValue(attr);
273 
274   if (attribute.empty()) {
275     cerr << ReadFrom() << "Expecting numeric attribute value, but got no data"
276          << endl;
277     exit(-1);
278   }
279   else {
280     double number=0;
281     if (is_number(trim(attribute)))
282       number = atof(attribute.c_str());
283     else {
284       cerr << ReadFrom() << "Expecting numeric attribute value, but got: "
285            << attribute << endl;
286       exit(-1);
287     }
288 
289     return (number);
290   }
291 }
292 
293 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
294 
GetElement(unsigned int el)295 Element* Element::GetElement(unsigned int el)
296 {
297   if (children.size() > el) {
298     element_index = el;
299     return children[el];
300   }
301   else {
302     element_index = 0;
303     return 0L;
304   }
305 }
306 
307 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
308 
GetNextElement(void)309 Element* Element::GetNextElement(void)
310 {
311   if (children.size() > element_index+1) {
312     element_index++;
313     return children[element_index];
314   } else {
315     element_index = 0;
316     return 0L;
317   }
318 }
319 
320 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321 
GetDataLine(unsigned int i)322 string Element::GetDataLine(unsigned int i)
323 {
324   if (data_lines.size() > 0) return data_lines[i];
325   else return string("");
326 }
327 
328 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
329 
GetDataAsNumber(void)330 double Element::GetDataAsNumber(void)
331 {
332   if (data_lines.size() == 1) {
333     double number=0;
334     if (is_number(trim(data_lines[0])))
335       number = atof(data_lines[0].c_str());
336     else {
337       cerr << ReadFrom() << "Expected numeric value, but got: " << data_lines[0]
338            << endl;
339       exit(-1);
340     }
341 
342     return number;
343   } else if (data_lines.size() == 0) {
344     cerr << ReadFrom() << "Expected numeric value, but got no data" << endl;
345     exit(-1);
346   } else {
347     cerr << ReadFrom() << "Attempting to get single data value in element "
348          << "<" << name << ">" << endl
349          << " from multiple lines:" << endl;
350     for(unsigned int i=0; i<data_lines.size(); ++i)
351       cerr << data_lines[i] << endl;
352     exit(-1);
353   }
354 }
355 
356 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
357 
GetNumElements(const string & element_name)358 unsigned int Element::GetNumElements(const string& element_name)
359 {
360   unsigned int number_of_elements=0;
361   Element* el=FindElement(element_name);
362   while (el) {
363     number_of_elements++;
364     el=FindNextElement(element_name);
365   }
366   return number_of_elements;
367 }
368 
369 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 
FindElement(const string & el)371 Element* Element::FindElement(const string& el)
372 {
373   if (el.empty() && children.size() >= 1) {
374     element_index = 1;
375     return children[0];
376   }
377   for (unsigned int i=0; i<children.size(); i++) {
378     if (el == children[i]->GetName()) {
379       element_index = i+1;
380       return children[i];
381     }
382   }
383   element_index = 0;
384   return 0L;
385 }
386 
387 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
388 
FindNextElement(const string & el)389 Element* Element::FindNextElement(const string& el)
390 {
391   if (el.empty()) {
392     if (element_index < children.size()) {
393       return children[element_index++];
394     } else {
395       element_index = 0;
396       return 0L;
397     }
398   }
399   for (unsigned int i=element_index; i<children.size(); i++) {
400     if (el == children[i]->GetName()) {
401       element_index = i+1;
402       return children[i];
403     }
404   }
405   element_index = 0;
406   return 0L;
407 }
408 
409 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
410 
FindElementValueAsNumber(const string & el)411 double Element::FindElementValueAsNumber(const string& el)
412 {
413   Element* element = FindElement(el);
414   if (element) {
415     double value = element->GetDataAsNumber();
416     value = DisperseValue(element, value);
417     return value;
418   } else {
419     cerr << ReadFrom() << "Attempting to get non-existent element " << el
420          << endl;
421     exit(-1);
422   }
423 }
424 
425 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426 
FindElementValueAsBoolean(const string & el)427 bool Element::FindElementValueAsBoolean(const string& el)
428 {
429   Element* element = FindElement(el);
430   if (element) {
431     // check value as an ordinary number
432     double value = element->GetDataAsNumber();
433 
434     // now check how it should return data
435     if (value == 0) {
436       return false;
437     } else {
438       return true;
439     }
440   } else {
441     cerr << ReadFrom() << "Attempting to get non-existent element " << el << " ;returning false"
442          << endl;
443     return false;
444   }
445 }
446 
447 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 
FindElementValue(const string & el)449 string Element::FindElementValue(const string& el)
450 {
451   Element* element = FindElement(el);
452   if (element) {
453     return element->GetDataLine();
454   } else {
455     return "";
456   }
457 }
458 
459 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460 
FindElementValueAsNumberConvertTo(const string & el,const string & target_units)461 double Element::FindElementValueAsNumberConvertTo(const string& el, const string& target_units)
462 {
463   Element* element = FindElement(el);
464 
465   if (!element) {
466     cerr << ReadFrom() << "Attempting to get non-existent element " << el
467          << endl;
468     exit(-1);
469   }
470 
471   string supplied_units = element->GetAttributeValue("unit");
472 
473   if (!supplied_units.empty()) {
474     if (convert.find(supplied_units) == convert.end()) {
475       cerr << element->ReadFrom() << "Supplied unit: \""
476            << supplied_units << "\" does not exist (typo?)." << endl;
477       exit(-1);
478     }
479     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
480       cerr << element->ReadFrom() << "Supplied unit: \""
481            << supplied_units << "\" cannot be converted to " << target_units
482            << endl;
483       exit(-1);
484     }
485   }
486 
487   double value = element->GetDataAsNumber();
488 
489   // Sanity check for angular values
490   if ((supplied_units == "RAD") && (fabs(value) > 2 * M_PI)) {
491     cerr << element->ReadFrom() << element->GetName() << " value "
492          << value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
493          << endl;
494   }
495   if ((supplied_units == "DEG") && (fabs(value) > 360.0)) {
496     cerr << element->ReadFrom() << element->GetName() << " value "
497          << value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
498          << endl;
499   }
500 
501 
502   if (!supplied_units.empty()) {
503     value *= convert[supplied_units][target_units];
504   }
505 
506   if ((target_units == "RAD") && (fabs(value) > 2 * M_PI)) {
507     cerr << element->ReadFrom() << element->GetName() << " value "
508          << value << " RAD is outside the range [ -2*M_PI RAD ; +2*M_PI RAD ]"
509          << endl;
510   }
511   if ((target_units == "DEG") && (fabs(value) > 360.0)) {
512     cerr << element->ReadFrom() << element->GetName() << " value "
513          << value << " DEG is outside the range [ -360 DEG ; +360 DEG ]"
514          << endl;
515   }
516 
517   value = DisperseValue(element, value, supplied_units, target_units);
518 
519   return value;
520 }
521 
522 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
523 
FindElementValueAsNumberConvertFromTo(const string & el,const string & supplied_units,const string & target_units)524 double Element::FindElementValueAsNumberConvertFromTo( const string& el,
525                                                        const string& supplied_units,
526                                                        const string& target_units)
527 {
528   Element* element = FindElement(el);
529 
530   if (!element) {
531     cerr << "Attempting to get non-existent element " << el << endl;
532     exit(-1);
533   }
534 
535   if (!supplied_units.empty()) {
536     if (convert.find(supplied_units) == convert.end()) {
537       cerr << element->ReadFrom() << "Supplied unit: \""
538            << supplied_units << "\" does not exist (typo?)." << endl;
539       exit(-1);
540     }
541     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
542       cerr << element->ReadFrom() << "Supplied unit: \""
543            << supplied_units << "\" cannot be converted to " << target_units
544            << endl;
545       exit(-1);
546     }
547   }
548 
549   double value = element->GetDataAsNumber();
550   if (!supplied_units.empty()) {
551     value *= convert[supplied_units][target_units];
552   }
553 
554   value = DisperseValue(element, value, supplied_units, target_units);
555 
556   return value;
557 }
558 
559 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560 
FindElementTripletConvertTo(const string & target_units)561 FGColumnVector3 Element::FindElementTripletConvertTo( const string& target_units)
562 {
563   FGColumnVector3 triplet;
564   Element* item;
565   double value=0.0;
566   string supplied_units = GetAttributeValue("unit");
567 
568   if (!supplied_units.empty()) {
569     if (convert.find(supplied_units) == convert.end()) {
570       cerr << ReadFrom() << "Supplied unit: \""
571            << supplied_units << "\" does not exist (typo?)." << endl;
572       exit(-1);
573     }
574     if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
575       cerr << ReadFrom() << "Supplied unit: \""
576            << supplied_units << "\" cannot be converted to " << target_units
577            << endl;
578       exit(-1);
579     }
580   }
581 
582   item = FindElement("x");
583   if (!item) item = FindElement("roll");
584   if (item) {
585     value = item->GetDataAsNumber();
586     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
587     triplet(1) = DisperseValue(item, value, supplied_units, target_units);
588   } else {
589     triplet(1) = 0.0;
590   }
591 
592 
593   item = FindElement("y");
594   if (!item) item = FindElement("pitch");
595   if (item) {
596     value = item->GetDataAsNumber();
597     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
598     triplet(2) = DisperseValue(item, value, supplied_units, target_units);
599   } else {
600     triplet(2) = 0.0;
601   }
602 
603   item = FindElement("z");
604   if (!item) item = FindElement("yaw");
605   if (item) {
606     value = item->GetDataAsNumber();
607     if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
608     triplet(3) = DisperseValue(item, value, supplied_units, target_units);
609   } else {
610     triplet(3) = 0.0;
611   }
612 
613   return triplet;
614 }
615 
616 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
617 
DisperseValue(Element * e,double val,const std::string & supplied_units,const std::string & target_units)618 double Element::DisperseValue(Element *e, double val, const std::string& supplied_units,
619                               const std::string& target_units)
620 {
621   double value=val;
622 
623   bool disperse = false;
624   try {
625     char* num = getenv("JSBSIM_DISPERSE");
626     if (num) {
627       disperse = (atoi(num) == 1);  // set dispersions
628     }
629   } catch (...) {                   // if error set to false
630     disperse = false;
631     std::cerr << "Could not process JSBSIM_DISPERSE environment variable: Assumed NO dispersions." << endl;
632   }
633 
634   if (e->HasAttribute("dispersion") && disperse) {
635     double disp = e->GetAttributeValueAsNumber("dispersion");
636     if (!supplied_units.empty()) disp *= convert[supplied_units][target_units];
637     string attType = e->GetAttributeValue("type");
638     if (attType == "gaussian" || attType == "gaussiansigned") {
639       double grn = FGJSBBase::GaussianRandomNumber();
640     if (attType == "gaussian") {
641       value = val + disp*grn;
642       } else { // Assume gaussiansigned
643         value = (val + disp*grn)*(fabs(grn)/grn);
644       }
645     } else if (attType == "uniform" || attType == "uniformsigned") {
646       double urn = ((((double)rand()/RAND_MAX)-0.5)*2.0);
647       if (attType == "uniform") {
648       value = val + disp * urn;
649       } else { // Assume uniformsigned
650         value = (val + disp * urn)*(fabs(urn)/urn);
651       }
652     } else {
653       cerr << ReadFrom() << "Unknown dispersion type" << attType << endl;
654       exit(-1);
655     }
656 
657   }
658   return value;
659 }
660 
661 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
662 
Print(unsigned int level)663 void Element::Print(unsigned int level)
664 {
665   unsigned int i, spaces;
666 
667   level+=2;
668   for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
669   cout << "Element Name: " << name;
670 
671   map<string, string>::iterator it;
672   for (it = attributes.begin(); it != attributes.end(); ++it)
673     cout << "  " << it->first << " = " << it->second;
674 
675   cout << endl;
676   for (i=0; i<data_lines.size(); i++) {
677     for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
678     cout << data_lines[i] << endl;
679   }
680   for (i=0; i<children.size(); i++) {
681     children[i]->Print(level);
682   }
683 }
684 
685 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
686 
AddAttribute(const string & name,const string & value)687 void Element::AddAttribute(const string& name, const string& value)
688 {
689   attributes[name] = value;
690 }
691 
692 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
693 
AddData(string d)694 void Element::AddData(string d)
695 {
696   string::size_type string_start = d.find_first_not_of(" \t");
697   if (string_start != string::npos && string_start > 0) {
698     d.erase(0,string_start);
699   }
700   data_lines.push_back(d);
701 }
702 
703 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
704 
ReadFrom(void) const705 string Element::ReadFrom(void) const
706 {
707   ostringstream message;
708 
709   message << endl
710           << "In file " << GetFileName() << ": line " << GetLineNumber()
711           << endl;
712 
713   return message.str();
714 }
715 
716 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717 
MergeAttributes(Element * el)718 void Element::MergeAttributes(Element* el)
719 {
720   map<string, string>::iterator it;
721 
722   for (it=el->attributes.begin(); it != el->attributes.end(); ++it) {
723     if (attributes.find(it->first) == attributes.end())
724       attributes[it->first] = it->second;
725     else {
726       if (FGJSBBase::debug_lvl > 0 && (attributes[it->first] != it->second))
727         cout << el->ReadFrom() << " Attribute '" << it->first << "' is overridden in file "
728              << GetFileName() << ": line " << GetLineNumber() << endl
729              << " The value '" << attributes[it->first] << "' will be used instead of '"
730              << it->second << "'." << endl;
731     }
732   }
733 }
734 
735 } // end namespace JSBSim
736